Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec...
authorDavid S. Miller <davem@davemloft.net>
Tue, 18 Mar 2014 18:09:07 +0000 (14:09 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 18 Mar 2014 18:09:07 +0000 (14:09 -0400)
Steffen Klassert says:

====================
One patch to rename a newly introduced struct. The rest is
the rework of the IPsec virtual tunnel interface for ipv6 to
support inter address family tunneling and namespace crossing.

1) Rename the newly introduced struct xfrm_filter to avoid a
   conflict with iproute2. From Nicolas Dichtel.

2) Introduce xfrm_input_afinfo to access the address family
   dependent tunnel callback functions properly.

3) Add and use a IPsec protocol multiplexer for ipv6.

4) Remove dst_entry caching. vti can lookup multiple different
   dst entries, dependent of the configured xfrm states. Therefore
   it does not make to cache a dst_entry.

5) Remove caching of flow informations. vti6 does not use the the
   tunnel endpoint addresses to do route and xfrm lookups.

6) Update the vti6 to use its own receive hook.

7) Remove the now unused xfrm_tunnel_notifier. This was used from vti
   and is replaced by the IPsec protocol multiplexer hooks.

8) Support inter address family tunneling for vti6.

9) Check if the tunnel endpoints of the xfrm state and the vti interface
   are matching and return an error otherwise.

10) Enable namespace crossing for vti devices.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1319 files changed:
Documentation/ABI/testing/sysfs-tty
Documentation/DocBook/80211.tmpl
Documentation/PCI/MSI-HOWTO.txt
Documentation/device-mapper/cache.txt
Documentation/device-mapper/thin-provisioning.txt
Documentation/devices.txt
Documentation/devicetree/bindings/arm/omap/omap.txt
Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
Documentation/devicetree/bindings/net/altera_tse.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/opencores-ethoc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt [deleted file]
Documentation/networking/altera_tse.txt [new file with mode: 0644]
Documentation/networking/can.txt
Documentation/networking/igb.txt
Documentation/networking/packet_mmap.txt
Documentation/networking/rxrpc.txt
Documentation/networking/timestamping.txt
MAINTAINERS
Makefile
arch/arc/mm/cache_arc700.c
arch/arm/Kconfig
arch/arm/boot/compressed/.gitignore
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am335x-evmsk.dts
arch/arm/boot/dts/armada-xp-mv78260.dtsi
arch/arm/boot/dts/bcm11351.dtsi
arch/arm/boot/dts/dove.dtsi
arch/arm/boot/dts/keystone-clocks.dtsi
arch/arm/boot/dts/omap3-gta04.dts
arch/arm/boot/dts/omap3-igep0020.dts
arch/arm/boot/dts/omap3-igep0030.dts
arch/arm/boot/dts/omap3-n9.dts
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap3-n950.dts
arch/arm/boot/dts/omap3-overo-storm-tobi.dts [new file with mode: 0644]
arch/arm/boot/dts/omap3-overo-tobi-common.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap3-overo-tobi.dts [new file with mode: 0644]
arch/arm/boot/dts/omap3-overo.dtsi
arch/arm/boot/dts/omap3-tobi.dts [deleted file]
arch/arm/boot/dts/sun4i-a10.dtsi
arch/arm/boot/dts/sun5i-a10s.dtsi
arch/arm/boot/dts/sun5i-a13.dtsi
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/boot/dts/tegra114.dtsi
arch/arm/boot/dts/tegra20.dtsi
arch/arm/boot/dts/tegra30-cardhu.dtsi
arch/arm/boot/dts/tegra30.dtsi
arch/arm/boot/dts/testcases/tests-interrupts.dtsi [deleted file]
arch/arm/boot/dts/testcases/tests-phandle.dtsi [deleted file]
arch/arm/boot/dts/testcases/tests.dtsi [deleted file]
arch/arm/boot/dts/versatile-pb.dts
arch/arm/configs/tegra_defconfig
arch/arm/include/asm/memory.h
arch/arm/kernel/head-common.S
arch/arm/kernel/head.S
arch/arm/kvm/arm.c
arch/arm/kvm/interrupts.S
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/common.h
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/cclock3xxx_data.c
arch/arm/mach-omap2/cpuidle44xx.c
arch/arm/mach-omap2/dpll3xxx.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/prminst44xx.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-sa1100/include/mach/collie.h
arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/tegra.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/dump.c
arch/arm64/include/asm/percpu.h
arch/arm64/include/asm/pgtable.h
arch/arm64/kernel/stacktrace.c
arch/arm64/kvm/hyp.S
arch/c6x/include/asm/cache.h
arch/cris/include/asm/bitops.h
arch/ia64/kernel/uncached.c
arch/m68k/include/asm/Kbuild
arch/m68k/include/asm/barrier.h [deleted file]
arch/m68k/include/asm/unistd.h
arch/m68k/include/uapi/asm/unistd.h
arch/m68k/kernel/syscalltable.S
arch/powerpc/include/asm/compat.h
arch/powerpc/include/asm/opal.h
arch/powerpc/include/asm/ptrace.h
arch/powerpc/kernel/crash_dump.c
arch/powerpc/kernel/ftrace.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/reloc_64.S
arch/powerpc/kernel/signal_64.c
arch/powerpc/platforms/cell/ras.c
arch/powerpc/platforms/powernv/eeh-ioda.c
arch/powerpc/platforms/powernv/opal-xscom.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/s390/kernel/compat_wrapper.S
arch/s390/pci/pci_dma.c
arch/sh/include/cpu-sh2/cpu/cache.h
arch/sh/include/cpu-sh2a/cpu/cache.h
arch/sh/include/cpu-sh3/cpu/cache.h
arch/sh/include/cpu-sh4/cpu/cache.h
arch/sh/kernel/cpu/init.c
arch/sh/mm/cache-debugfs.c
arch/sh/mm/cache-sh2.c
arch/sh/mm/cache-sh2a.c
arch/sh/mm/cache-sh4.c
arch/sh/mm/cache-shx3.c
arch/sh/mm/cache.c
arch/sparc/Kconfig
arch/sparc/mm/srmmu.c
arch/x86/Kconfig.cpu
arch/x86/boot/compressed/aslr.c
arch/x86/include/asm/barrier.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/io.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/tsc.h
arch/x86/kernel/cpu/centaur.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_p6.c
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/i387.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/quirks.c
arch/x86/kernel/setup.c
arch/x86/kernel/tsc.c
arch/x86/kernel/tsc_msr.c
arch/x86/kvm/mmu.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/fault.c
arch/x86/net/bpf_jit.S
arch/x86/platform/efi/efi.c
arch/x86/um/asm/barrier.h
arch/xtensa/Kconfig
arch/xtensa/boot/dts/xtfpga.dtsi
arch/xtensa/include/asm/io.h
arch/xtensa/include/asm/traps.h
arch/xtensa/include/asm/vectors.h
arch/xtensa/include/uapi/asm/unistd.h
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/time.c
arch/xtensa/kernel/vectors.S
arch/xtensa/kernel/xtensa_ksyms.c
arch/xtensa/mm/init.c
arch/xtensa/mm/mmu.c
arch/xtensa/platforms/xtfpga/setup.c
arch/xtensa/variants/fsf/include/variant/tie.h
block/blk-cgroup.h
block/blk-exec.c
block/blk-flush.c
block/blk-mq-cpu.c
block/blk-mq.c
block/blk-mq.h
drivers/acpi/ac.c
drivers/acpi/battery.c
drivers/acpi/blacklist.c
drivers/acpi/button.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/fan.c
drivers/acpi/pci_irq.c
drivers/acpi/processor_throttling.c
drivers/acpi/resource.c
drivers/acpi/sbs.c
drivers/acpi/sleep.c
drivers/acpi/thermal.c
drivers/acpi/video.c
drivers/acpi/video_detect.c
drivers/ata/Kconfig
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-pmp.c
drivers/ata/pata_imx.c
drivers/ata/sata_mv.c
drivers/ata/sata_sil.c
drivers/base/firmware_class.c
drivers/block/aoe/aoecmd.c
drivers/block/mtip32xx/mtip32xx.h
drivers/block/zram/zram_drv.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_vhci.c
drivers/clk/at91/clk-master.c
drivers/clk/clk-nomadik.c
drivers/clk/clk.c
drivers/clk/keystone/gate.c
drivers/clk/mvebu/armada-370.c
drivers/clk/mvebu/armada-xp.c
drivers/clk/mvebu/dove.c
drivers/clk/mvebu/kirkwood.c
drivers/clk/shmobile/clk-rcar-gen2.c
drivers/clk/tegra/clk-divider.c
drivers/clk/tegra/clk-id.h
drivers/clk/tegra/clk-tegra-periph.c
drivers/clk/tegra/clk-tegra-super-gen4.c
drivers/clk/tegra/clk-tegra114.c
drivers/clk/tegra/clk-tegra124.c
drivers/clk/tegra/clk-tegra20.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/powernow-k8.c
drivers/dma/imx-sdma.c
drivers/dma/ioat/dma.c
drivers/dma/ioat/dma.h
drivers/dma/ioat/dma_v2.c
drivers/dma/ioat/dma_v3.c
drivers/dma/ste_dma40.c
drivers/edac/i7300_edac.c
drivers/edac/i7core_edac.c
drivers/extcon/extcon-arizona.c
drivers/firewire/core-device.c
drivers/firewire/net.c
drivers/firewire/ohci.c
drivers/firewire/sbp2.c
drivers/fmc/fmc-write-eeprom.c
drivers/gpu/drm/armada/armada_drv.c
drivers/gpu/drm/bochs/Kconfig
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/evergreen_smc.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_audio.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_atpx_handler.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/rgb.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/vmwgfx/svga3d_reg.h
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
drivers/gpu/host1x/job.c
drivers/hwmon/max1668.c
drivers/i2c/busses/Kconfig
drivers/iio/gyro/Kconfig
drivers/iio/gyro/st_gyro.h
drivers/iio/gyro/st_gyro_core.c
drivers/iio/gyro/st_gyro_i2c.c
drivers/iio/gyro/st_gyro_spi.c
drivers/iio/light/cm32181.c
drivers/iio/light/cm36651.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/cxgb4/t4.h
drivers/infiniband/hw/cxgb4/user.h
drivers/infiniband/hw/mlx4/cm.c
drivers/infiniband/hw/mlx4/cq.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/mcg.c
drivers/infiniband/hw/mlx4/mlx4_ib.h
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/input/misc/arizona-haptics.c
drivers/iommu/arm-smmu.c
drivers/iommu/omap-iommu-debug.c
drivers/irqchip/irq-metag-ext.c
drivers/irqchip/irq-metag.c
drivers/irqchip/irq-orion.c
drivers/md/Kconfig
drivers/md/dm-cache-policy-mq.c
drivers/md/dm-cache-target.c
drivers/md/dm-io.c
drivers/md/dm-mpath.c
drivers/md/dm-raid1.c
drivers/md/dm-snap-persistent.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin-metadata.h
drivers/md/dm-thin.c
drivers/md/persistent-data/Kconfig
drivers/md/persistent-data/dm-space-map-metadata.c
drivers/md/persistent-data/dm-space-map-metadata.h
drivers/mfd/da9055-i2c.c
drivers/mfd/max14577.c
drivers/mfd/max8997.c
drivers/mfd/max8998.c
drivers/mfd/sec-core.c
drivers/mfd/tps65217.c
drivers/mfd/wm8994-core.c
drivers/misc/mei/client.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/omap2.c
drivers/mtd/ubi/fastmap.c
drivers/net/Kconfig
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_netlink.c
drivers/net/bonding/bond_options.c
drivers/net/bonding/bond_options.h
drivers/net/bonding/bond_procfs.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/can/janz-ican3.c
drivers/net/can/mcp251x.c
drivers/net/dummy.c
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/altera/Kconfig [new file with mode: 0644]
drivers/net/ethernet/altera/Makefile [new file with mode: 0644]
drivers/net/ethernet/altera/altera_msgdma.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_msgdma.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_msgdmahw.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_sgdma.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_sgdma.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_sgdmahw.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_tse.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_tse_ethtool.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_tse_main.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_utils.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_utils.h [new file with mode: 0644]
drivers/net/ethernet/amd/amd8111e.c
drivers/net/ethernet/broadcom/b44.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/bnx2.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/brocade/bna/bfa_ioc.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/cisco/enic/enic_main.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/fec_main.c
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/ibm/ibmveth.h
drivers/net/ethernet/intel/e1000e/80003es2lan.c
drivers/net/ethernet/intel/e1000e/80003es2lan.h
drivers/net/ethernet/intel/e1000e/82571.c
drivers/net/ethernet/intel/e1000e/82571.h
drivers/net/ethernet/intel/e1000e/Makefile
drivers/net/ethernet/intel/e1000e/defines.h
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ethtool.c
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/ich8lan.h
drivers/net/ethernet/intel/e1000e/mac.c
drivers/net/ethernet/intel/e1000e/mac.h
drivers/net/ethernet/intel/e1000e/manage.c
drivers/net/ethernet/intel/e1000e/manage.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/e1000e/nvm.c
drivers/net/ethernet/intel/e1000e/nvm.h
drivers/net/ethernet/intel/e1000e/param.c
drivers/net/ethernet/intel/e1000e/phy.c
drivers/net/ethernet/intel/e1000e/phy.h
drivers/net/ethernet/intel/e1000e/ptp.c
drivers/net/ethernet/intel/e1000e/regs.h
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_dcb.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.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_txrx.c
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40evf/i40e_common.c
drivers/net/ethernet/intel/i40evf/i40e_prototype.h
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_type.h
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_82575.h
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgb/ixgb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_main.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/port.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/neterion/vxge/vxge-main.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/realtek/8139too.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/falcon.c
drivers/net/ethernet/sfc/farch.c
drivers/net/ethernet/sfc/filter.h
drivers/net/ethernet/sfc/mcdi.c
drivers/net/ethernet/sfc/mcdi_port.c
drivers/net/ethernet/sfc/ptp.c
drivers/net/ethernet/sfc/selftest.c
drivers/net/ethernet/sfc/siena_sriov.c
drivers/net/ethernet/stmicro/stmmac/chain_mode.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/tile/tilegx.c
drivers/net/ethernet/tile/tilepro.c
drivers/net/ethernet/toshiba/tc35815.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/ethernet/xilinx/xilinx_axienet_main.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/ieee802154/Kconfig
drivers/net/ieee802154/at86rf230.c
drivers/net/ieee802154/fakehard.c
drivers/net/ieee802154/mrf24j40.c
drivers/net/ifb.c
drivers/net/loopback.c
drivers/net/macvlan.c
drivers/net/nlmon.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/team/team.c
drivers/net/team/team_mode_loadbalance.c
drivers/net/tun.c
drivers/net/usb/Makefile
drivers/net/usb/ax88179_178a.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/lg-vl600.c
drivers/net/usb/r8152.c
drivers/net/usb/r815x.c [deleted file]
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/wireless/Kconfig
drivers/net/wireless/airo.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.h
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/txrx.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath6kl/usb.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/common-init.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/common-init.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/ath/wil6210/Makefile
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/debugfs.c
drivers/net/wireless/ath/wil6210/main.c
drivers/net/wireless/ath/wil6210/rx_reorder.c [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/txrx.h
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/atmel.c
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43/debugfs.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/pio.c
drivers/net/wireless/b43/sysfs.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/sysfs.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
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/cw1200/fwio.c
drivers/net/wireless/hostap/hostap_ap.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/commands.h
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlwifi/dvm/agn.h
drivers/net/wireless/iwlwifi/dvm/devices.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/rx.c
drivers/net/wireless/iwlwifi/dvm/sta.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.h
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-modparams.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.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/rs.c
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/time-event.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/tx.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mac80211_hwsim.h
drivers/net/wireless/mwifiex/11ac.c
drivers/net/wireless/mwifiex/11h.c
drivers/net/wireless/mwifiex/11n.c
drivers/net/wireless/mwifiex/11n_rxreorder.c
drivers/net/wireless/mwifiex/11n_rxreorder.h
drivers/net/wireless/mwifiex/README
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cfp.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/debugfs.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/ie.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/pcie.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sdio.h
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/tdls.c
drivers/net/wireless/mwifiex/uap_cmd.c
drivers/net/wireless/mwifiex/uap_event.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/util.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/cfg.c
drivers/net/wireless/orinoco/hw.c
drivers/net/wireless/orinoco/scan.c
drivers/net/wireless/orinoco/wext.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00debug.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtlwifi/Kconfig
drivers/net/wireless/rtlwifi/Makefile
drivers/net/wireless/rtlwifi/btcoexist/Makefile [new file with mode: 0644]
drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/core.h
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/pci.h
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/ps.h
drivers/net/wireless/rtlwifi/rtl8188ee/Makefile
drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
drivers/net/wireless/rtlwifi/rtl8192de/dm.c
drivers/net/wireless/rtlwifi/rtl8192de/hw.c
drivers/net/wireless/rtlwifi/rtl8192de/phy.c
drivers/net/wireless/rtlwifi/rtl8192de/reg.h
drivers/net/wireless/rtlwifi/rtl8192de/rf.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.h
drivers/net/wireless/rtlwifi/rtl8192se/hw.c
drivers/net/wireless/rtlwifi/rtl8192se/phy.c
drivers/net/wireless/rtlwifi/rtl8192se/reg.h
drivers/net/wireless/rtlwifi/rtl8192se/rf.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.h
drivers/net/wireless/rtlwifi/rtl8723ae/Makefile
drivers/net/wireless/rtlwifi/rtl8723ae/def.h
drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c
drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
drivers/net/wireless/rtlwifi/rtl8723ae/phy.h
drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h
drivers/net/wireless/rtlwifi/rtl8723ae/reg.h
drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
drivers/net/wireless/rtlwifi/rtl8723ae/trx.h
drivers/net/wireless/rtlwifi/rtl8723be/Makefile [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/def.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/dm.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/dm.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/fw.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/fw.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/hw.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/hw.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/led.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/led.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/phy.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/phy.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/reg.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/rf.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/rf.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/sw.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/sw.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/table.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/table.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/trx.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723be/trx.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723com/Makefile [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723com/main.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/ti/wilink_platform_data.c
drivers/net/wireless/ti/wl1251/cmd.c
drivers/net/wireless/ti/wl1251/rx.c
drivers/net/wireless/ti/wl1251/sdio.c
drivers/net/wireless/ti/wl1251/spi.c
drivers/net/wireless/ti/wl1251/wl1251.h
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/spi.c
drivers/net/wireless/ti/wlcore/sysfs.c
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zd1201.c
drivers/net/xen-netback/common.h
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netfront.c
drivers/of/base.c
drivers/of/selftest.c
drivers/of/testcase-data/testcases.dtsi [new file with mode: 0644]
drivers/of/testcase-data/tests-interrupts.dtsi [new file with mode: 0644]
drivers/of/testcase-data/tests-match.dtsi [new file with mode: 0644]
drivers/of/testcase-data/tests-phandle.dtsi [new file with mode: 0644]
drivers/pci/bus.c
drivers/pci/host/pci-mvebu.c
drivers/pci/msi.c
drivers/pci/pci.c
drivers/phy/Kconfig
drivers/phy/phy-core.c
drivers/phy/phy-exynos-dp-video.c
drivers/phy/phy-exynos-mipi-video.c
drivers/phy/phy-mvebu-sata.c
drivers/phy/phy-omap-usb2.c
drivers/phy/phy-twl4030-usb.c
drivers/pinctrl/Kconfig
drivers/pinctrl/pinctrl-capri.c
drivers/pinctrl/pinctrl-sunxi.c
drivers/pinctrl/pinctrl-sunxi.h
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/pinctrl/sirf/pinctrl-sirf.c
drivers/pnp/pnpacpi/rsparser.c
drivers/pwm/pwm-lp3943.c
drivers/rapidio/devices/tsi721.h
drivers/rapidio/devices/tsi721_dma.c
drivers/regulator/core.c
drivers/regulator/da9063-regulator.c
drivers/regulator/max14577.c
drivers/regulator/s5m8767.c
drivers/rtc/rtc-s3c.c
drivers/s390/cio/chsc.c
drivers/s390/crypto/zcrypt_msgtype6.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/sbus/char/jsflash.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/qla2xxx/tcm_qla2xxx.h
drivers/spi/spi-ath79.c
drivers/spi/spi-atmel.c
drivers/spi/spi-coldfire-qspi.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-imx.c
drivers/spi/spi-topcliff-pch.c
drivers/staging/android/binder.c
drivers/staging/cxt1e1/linux.c
drivers/staging/iio/adc/mxs-lradc.c
drivers/staging/rtl8188eu/os_dep/usb_intf.c
drivers/staging/rtl8821ae/rtl8821ae/trx.c
drivers/staging/wlan-ng/cfg80211.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl2.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/target_core_sbc.c
drivers/target/target_core_transport.c
drivers/thermal/Kconfig
drivers/thermal/thermal_core.c
drivers/thermal/x86_pkg_temp_thermal.c
drivers/tty/tty_io.c
drivers/usb/chipidea/udc.c
drivers/usb/core/config.c
drivers/usb/core/quirks.c
drivers/usb/gadget/bcm63xx_udc.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/printer.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/xhci.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_virthub.c
drivers/usb/musb/omap2430.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/scsi.c
drivers/watchdog/w83697hf_wdt.c
fs/bio-integrity.c
fs/cifs/cifsglob.h
fs/cifs/file.c
fs/cifs/transport.c
fs/file.c
fs/file_table.c
fs/fs-writeback.c
fs/hfsplus/catalog.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/hfsplus_raw.h
fs/hfsplus/inode.c
fs/hfsplus/options.c
fs/kernfs/mount.c
fs/namei.c
fs/nfs/delegation.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3proc.c
fs/nfs/nfs4client.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/notify/dnotify/dnotify.c
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify_user.c
fs/notify/fsnotify.c
fs/notify/group.c
fs/notify/inotify/inotify.h
fs/notify/inotify/inotify_fsnotify.c
fs/notify/inotify/inotify_user.c
fs/notify/notification.c
fs/ocfs2/file.c
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/open.c
fs/proc/base.c
fs/proc/page.c
fs/quota/dquot.c
fs/read_write.c
fs/sync.c
fs/sysfs/mount.c
fs/udf/file.c
fs/udf/inode.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_sb.c
fs/xfs/xfs_super.c
include/dt-bindings/clock/tegra124-car.h
include/kvm/arm_vgic.h
include/linux/audit.h
include/linux/blk-mq.h
include/linux/can/dev.h
include/linux/cgroup.h
include/linux/clk/ti.h
include/linux/file.h
include/linux/firewire.h
include/linux/fs.h
include/linux/fsnotify_backend.h
include/linux/gfp.h
include/linux/huge_mm.h
include/linux/ieee80211.h
include/linux/ipc_namespace.h
include/linux/kernfs.h
include/linux/mfd/max8997-private.h
include/linux/mfd/max8998-private.h
include/linux/mfd/tps65217.h
include/linux/miscdevice.h
include/linux/mlx4/cmd.h
include/linux/mlx4/device.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/netdevice.h
include/linux/netfilter/ipset/ip_set.h
include/linux/netfilter/nfnetlink.h
include/linux/netpoll.h
include/linux/nfs_xdr.h
include/linux/pci.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/syscalls.h
include/linux/tracepoint.h
include/linux/tty.h
include/linux/u64_stats_sync.h
include/linux/wl12xx.h
include/linux/workqueue.h
include/linux/writeback.h
include/net/6lowpan.h [new file with mode: 0644]
include/net/af_ieee802154.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
include/net/bluetooth/rfcomm.h
include/net/cfg80211.h
include/net/dst.h
include/net/flow.h
include/net/ieee802154.h
include/net/ieee802154_netdev.h
include/net/ip.h
include/net/ip_tunnels.h
include/net/mac80211.h
include/net/mac802154.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_conntrack_core.h
include/net/netfilter/nf_conntrack_labels.h
include/net/netfilter/nf_tables.h
include/net/netns/conntrack.h
include/net/netns/xfrm.h
include/net/nl802154.h
include/net/sock.h
include/net/tcp.h
include/net/xfrm.h
include/sound/soc-dapm.h
include/target/iscsi/iscsi_transport.h
include/trace/events/sunrpc.h
include/trace/events/writeback.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/can/netlink.h
include/uapi/linux/if_ether.h
include/uapi/linux/netfilter/ipset/ip_set.h
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/nl80211.h
init/main.c
ipc/mq_sysctl.c
ipc/mqueue.c
kernel/audit.c
kernel/audit.h
kernel/audit_tree.c
kernel/audit_watch.c
kernel/auditfilter.c
kernel/cgroup.c
kernel/cpuset.c
kernel/events/core.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/power/console.c
kernel/profile.c
kernel/sched/core.c
kernel/sched/cpudeadline.c
kernel/sched/deadline.c
kernel/sched/fair.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/time/sched_clock.c
kernel/trace/trace_events.c
kernel/tracepoint.c
kernel/user_namespace.c
kernel/workqueue.c
lib/dma-debug.c
lib/radix-tree.c
mm/Kconfig
mm/compaction.c
mm/huge_memory.c
mm/ksm.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/migrate.c
mm/page_alloc.c
mm/swap.c
mm/vmpressure.c
net/8021q/vlan.h
net/8021q/vlan_core.c
net/8021q/vlan_dev.c
net/8021q/vlan_netlink.c
net/bluetooth/6lowpan.c
net/bluetooth/a2mp.c
net/bluetooth/af_bluetooth.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hci_sysfs.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/smp.c
net/bluetooth/smp.h
net/bridge/br_device.c
net/bridge/br_multicast.c
net/bridge/br_netfilter.c
net/can/raw.c
net/core/dev.c
net/core/flow.c
net/core/flow_dissector.c
net/core/neighbour.c
net/core/netpoll.c
net/core/skbuff.c
net/core/sock.c
net/hsr/hsr_framereg.c
net/ieee802154/6lowpan.h [deleted file]
net/ieee802154/6lowpan_iphc.c
net/ieee802154/6lowpan_rtnl.c
net/ieee802154/Kconfig
net/ieee802154/Makefile
net/ieee802154/af802154.h
net/ieee802154/af_ieee802154.c
net/ieee802154/dgram.c
net/ieee802154/header_ops.c [new file with mode: 0644]
net/ieee802154/nl-mac.c
net/ieee802154/raw.c
net/ieee802154/reassembly.c
net/ieee802154/reassembly.h
net/ipv4/af_inet.c
net/ipv4/inet_fragment.c
net/ipv4/ip_output.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_tunnel_core.c
net/ipv4/netfilter.c
net/ipv4/netfilter/nf_nat_snmp_basic.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv6/Kconfig
net/ipv6/addrconf.c
net/ipv6/exthdrs_core.c
net/ipv6/exthdrs_offload.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/output_core.c
net/ipv6/ping.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/udp_offload.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_netlink.c
net/l2tp/l2tp_ppp.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs_netdev.c
net/mac80211/driver-ops.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh_ps.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mac802154/Makefile
net/mac802154/ieee802154_dev.c
net/mac802154/mac802154.h
net/mac802154/mac_cmd.c
net/mac802154/mib.c
net/mac802154/wpan.c
net/netfilter/ipset/Kconfig
net/netfilter/ipset/Makefile
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/ipset/ip_set_hash_ip.c
net/netfilter/ipset/ip_set_hash_ipmark.c [new file with mode: 0644]
net/netfilter/ipset/ip_set_hash_ipport.c
net/netfilter/ipset/ip_set_hash_ipportip.c
net/netfilter/ipset/ip_set_hash_ipportnet.c
net/netfilter/ipset/ip_set_hash_net.c
net/netfilter/ipset/ip_set_hash_netiface.c
net/netfilter/ipset/ip_set_hash_netnet.c
net/netfilter/ipset/ip_set_hash_netport.c
net/netfilter/ipset/ip_set_hash_netportnet.c
net/netfilter/ipset/pfxlen.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_lblc.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_nat_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink.c
net/netfilter/nfnetlink_log.c
net/netfilter/nft_compat.c
net/netfilter/nft_ct.c
net/netfilter/nft_hash.c
net/netfilter/nft_immediate.c
net/netfilter/nft_log.c
net/netfilter/nft_lookup.c
net/netfilter/nft_meta.c
net/netfilter/nft_nat.c
net/netfilter/nft_payload.c
net/netfilter/nft_reject_inet.c
net/netfilter/xt_AUDIT.c
net/netfilter/xt_connlimit.c
net/netfilter/xt_ipcomp.c
net/netlink/af_netlink.c
net/netlink/af_netlink.h
net/nfc/nci/core.c
net/openvswitch/datapath.c
net/openvswitch/vport.c
net/rxrpc/Makefile
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-ack.c
net/rxrpc/ar-call.c
net/rxrpc/ar-connection.c
net/rxrpc/ar-error.c
net/rxrpc/ar-input.c
net/rxrpc/ar-internal.h
net/rxrpc/ar-output.c
net/rxrpc/ar-recvmsg.c
net/rxrpc/ar-skbuff.c
net/rxrpc/ar-transport.c
net/rxrpc/sysctl.c [new file with mode: 0644]
net/sched/sch_api.c
net/sched/sch_atm.c
net/sched/sch_cbq.c
net/sched/sch_fq.c
net/sched/sch_fq_codel.c
net/sched/sch_hfsc.c
net/sched/sch_hhf.c
net/sched/sch_htb.c
net/sched/sch_ingress.c
net/sched/sch_tbf.c
net/sctp/associola.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/socket.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/backchannel_rqst.c
net/sunrpc/xprtsock.c
net/tipc/bearer.c
net/tipc/config.c
net/tipc/core.c
net/tipc/core.h
net/tipc/handler.c
net/tipc/link.c
net/tipc/name_table.c
net/tipc/netlink.c
net/tipc/port.c
net/tipc/port.h
net/tipc/ref.c
net/tipc/ref.h
net/tipc/server.c
net/tipc/server.h
net/tipc/socket.c
net/tipc/socket.h [new file with mode: 0644]
net/tipc/subscr.c
net/unix/af_unix.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/genregdb.awk
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/reg.c
net/wireless/trace.h
net/wireless/util.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
scripts/Makefile.lib
scripts/gen_initramfs_list.sh
scripts/mod/modpost.c
security/keys/keyring.c
security/selinux/ss/policydb.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/soc/blackfin/Kconfig
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/da732x.c
sound/soc/codecs/da9055.c
sound/soc/codecs/isabelle.c
sound/soc/codecs/max98090.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/si476x.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_esai.h
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-sgtl5000.c
sound/soc/fsl/imx-wm8962.c
sound/soc/omap/n810.c
sound/soc/samsung/Kconfig
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/txx9/txx9aclc-ac97.c
sound/usb/mixer.c
sound/usb/mixer_maps.c
tools/lib/lockdep/Makefile
tools/lib/lockdep/preload.c
tools/lib/lockdep/run_tests.sh [changed mode: 0644->0755]
tools/lib/lockdep/uinclude/asm/hash.h [new file with mode: 0644]
tools/lib/lockdep/uinclude/linux/rcu.h
tools/net/Makefile
tools/perf/builtin-report.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/config/feature-checks/Makefile
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/include/linux/bitops.h
tools/perf/util/parse-events.c
tools/perf/util/probe-event.c
tools/perf/util/session.c
tools/perf/util/symbol.c
tools/testing/selftests/ipc/msgque.c

index a2ccec35ffce2cedb601d4cad55012b56a3c4e6f..ad22fb0ee765b792a3bc0ab7f9d2995c69f1d5d0 100644 (file)
@@ -3,8 +3,7 @@ Date:           Nov 2010
 Contact:       Kay Sievers <kay.sievers@vrfy.org>
 Description:
                 Shows the list of currently configured
-                tty devices used for the console,
-                like 'tty1 ttyS0'.
+                console devices, like 'tty1 ttyS0'.
                 The last entry in the file is the active
                 device connected to /dev/console.
                 The file supports poll() to detect virtual
index 46ad6faee9ab73dfae2fa3e2b00bb6fb7f1c63a1..044b76436e8373ae601f9c60bd274754f3df6033 100644 (file)
@@ -98,6 +98,8 @@
 !Finclude/net/cfg80211.h priv_to_wiphy
 !Finclude/net/cfg80211.h set_wiphy_dev
 !Finclude/net/cfg80211.h wdev_priv
+!Finclude/net/cfg80211.h ieee80211_iface_limit
+!Finclude/net/cfg80211.h ieee80211_iface_combination
       </chapter>
       <chapter>
       <title>Actions and configuration</title>
index a8d01005f480ad6be4c86f187665e9ef3d75d08e..10a93696e55ad33c821a5466ed813a07e9fb9930 100644 (file)
@@ -82,7 +82,19 @@ Most of the hard work is done for the driver in the PCI layer.  It simply
 has to request that the PCI layer set up the MSI capability for this
 device.
 
-4.2.1 pci_enable_msi_range
+4.2.1 pci_enable_msi
+
+int pci_enable_msi(struct pci_dev *dev)
+
+A successful call allocates ONE interrupt to the device, regardless
+of how many MSIs the device supports.  The device is switched from
+pin-based interrupt mode to MSI mode.  The dev->irq number is changed
+to a new number which represents the message signaled interrupt;
+consequently, this function should be called before the driver calls
+request_irq(), because an MSI is delivered via a vector that is
+different from the vector of a pin-based interrupt.
+
+4.2.2 pci_enable_msi_range
 
 int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
 
@@ -147,6 +159,11 @@ static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
        return pci_enable_msi_range(pdev, nvec, nvec);
 }
 
+Note, unlike pci_enable_msi_exact() function, which could be also used to
+enable a particular number of MSI-X interrupts, pci_enable_msi_range()
+returns either a negative errno or 'nvec' (not negative errno or 0 - as
+pci_enable_msi_exact() does).
+
 4.2.1.3 Single MSI mode
 
 The most notorious example of the request type described above is
@@ -158,7 +175,27 @@ static int foo_driver_enable_single_msi(struct pci_dev *pdev)
        return pci_enable_msi_range(pdev, 1, 1);
 }
 
-4.2.2 pci_disable_msi
+Note, unlike pci_enable_msi() function, which could be also used to
+enable the single MSI mode, pci_enable_msi_range() returns either a
+negative errno or 1 (not negative errno or 0 - as pci_enable_msi()
+does).
+
+4.2.3 pci_enable_msi_exact
+
+int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+
+This variation on pci_enable_msi_range() call allows a device driver to
+request exactly 'nvec' MSIs.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to request any more MSI interrupts for
+this device.
+
+By contrast with pci_enable_msi_range() function, pci_enable_msi_exact()
+returns zero in case of success, which indicates MSI interrupts have been
+successfully allocated.
+
+4.2.4 pci_disable_msi
 
 void pci_disable_msi(struct pci_dev *dev)
 
@@ -172,7 +209,7 @@ on any interrupt for which it previously called request_irq().
 Failure to do so results in a BUG_ON(), leaving the device with
 MSI enabled and thus leaking its vector.
 
-4.2.3 pci_msi_vec_count
+4.2.4 pci_msi_vec_count
 
 int pci_msi_vec_count(struct pci_dev *dev)
 
@@ -257,8 +294,8 @@ possible, likely up to the limit returned by pci_msix_vec_count() function:
 
 static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
 {
-       return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
-                                   1, nvec);
+       return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                    1, nvec);
 }
 
 Note the value of 'minvec' parameter is 1.  As 'minvec' is inclusive,
@@ -269,8 +306,8 @@ In this case the function could look like this:
 
 static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
 {
-       return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
-                                   FOO_DRIVER_MINIMUM_NVEC, nvec);
+       return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                    FOO_DRIVER_MINIMUM_NVEC, nvec);
 }
 
 4.3.1.2 Exact number of MSI-X interrupts
@@ -282,10 +319,15 @@ parameters:
 
 static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
 {
-       return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
-                                   nvec, nvec);
+       return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                    nvec, nvec);
 }
 
+Note, unlike pci_enable_msix_exact() function, which could be also used to
+enable a particular number of MSI-X interrupts, pci_enable_msix_range()
+returns either a negative errno or 'nvec' (not negative errno or 0 - as
+pci_enable_msix_exact() does).
+
 4.3.1.3 Specific requirements to the number of MSI-X interrupts
 
 As noted above, there could be devices that can not operate with just any
@@ -332,7 +374,64 @@ Note how pci_enable_msix_range() return value is analized for a fallback -
 any error code other than -ENOSPC indicates a fatal error and should not
 be retried.
 
-4.3.2 pci_disable_msix
+4.3.2 pci_enable_msix_exact
+
+int pci_enable_msix_exact(struct pci_dev *dev,
+                         struct msix_entry *entries, int nvec)
+
+This variation on pci_enable_msix_range() call allows a device driver to
+request exactly 'nvec' MSI-Xs.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to allocate any more MSI-X interrupts for
+this device.
+
+By contrast with pci_enable_msix_range() function, pci_enable_msix_exact()
+returns zero in case of success, which indicates MSI-X interrupts have been
+successfully allocated.
+
+Another version of a routine that enables MSI-X mode for a device with
+specific requirements described in chapter 4.3.1.3 might look like this:
+
+/*
+ * Assume 'minvec' and 'maxvec' are non-zero
+ */
+static int foo_driver_enable_msix(struct foo_adapter *adapter,
+                                 int minvec, int maxvec)
+{
+       int rc;
+
+       minvec = roundup_pow_of_two(minvec);
+       maxvec = rounddown_pow_of_two(maxvec);
+
+       if (minvec > maxvec)
+               return -ERANGE;
+
+retry:
+       rc = pci_enable_msix_exact(adapter->pdev,
+                                  adapter->msix_entries, maxvec);
+
+       /*
+        * -ENOSPC is the only error code allowed to be analyzed
+        */
+       if (rc == -ENOSPC) {
+               if (maxvec == 1)
+                       return -ENOSPC;
+
+               maxvec /= 2;
+
+               if (minvec > maxvec)
+                       return -ENOSPC;
+
+               goto retry;
+       } else if (rc < 0) {
+               return rc;
+       }
+
+       return maxvec;
+}
+
+4.3.3 pci_disable_msix
 
 void pci_disable_msix(struct pci_dev *dev)
 
index e6b72d35515123ad0aff423999aeef359183bb3d..68c0f517c60edb1ab7a61e990720c7c8f097bb16 100644 (file)
@@ -124,12 +124,11 @@ the default being 204800 sectors (or 100MB).
 Updating on-disk metadata
 -------------------------
 
-On-disk metadata is committed every time a REQ_SYNC or REQ_FUA bio is
-written.  If no such requests are made then commits will occur every
-second.  This means the cache behaves like a physical disk that has a
-write cache (the same is true of the thin-provisioning target).  If
-power is lost you may lose some recent writes.  The metadata should
-always be consistent in spite of any crash.
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second.  This
+means the cache behaves like a physical disk that has a volatile write
+cache.  If power is lost you may lose some recent writes.  The metadata
+should always be consistent in spite of any crash.
 
 The 'dirty' state for a cache block changes far too frequently for us
 to keep updating it on the fly.  So we treat it as a hint.  In normal
index 8a7a3d46e0daa00d6f87315648b7cb292e8c05b4..05a27e9442bd4e5c4d3e618a6a0594e55466b192 100644 (file)
@@ -116,6 +116,35 @@ Resuming a device with a new table itself triggers an event so the
 userspace daemon can use this to detect a situation where a new table
 already exceeds the threshold.
 
+A low water mark for the metadata device is maintained in the kernel and
+will trigger a dm event if free space on the metadata device drops below
+it.
+
+Updating on-disk metadata
+-------------------------
+
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second.  This
+means the thin-provisioning target behaves like a physical disk that has
+a volatile write cache.  If power is lost you may lose some recent
+writes.  The metadata should always be consistent in spite of any crash.
+
+If data space is exhausted the pool will either error or queue IO
+according to the configuration (see: error_if_no_space).  If metadata
+space is exhausted or a metadata operation fails: the pool will error IO
+until the pool is taken offline and repair is performed to 1) fix any
+potential inconsistencies and 2) clear the flag that imposes repair.
+Once the pool's metadata device is repaired it may be resized, which
+will allow the pool to return to normal operation.  Note that if a pool
+is flagged as needing repair, the pool's data and metadata devices
+cannot be resized until repair is performed.  It should also be noted
+that when the pool's metadata space is exhausted the current metadata
+transaction is aborted.  Given that the pool will cache IO whose
+completion may have already been acknowledged to upper IO layers
+(e.g. filesystem) it is strongly suggested that consistency checks
+(e.g. fsck) be performed on those layers when repair of the pool is
+required.
+
 Thin provisioning
 -----------------
 
@@ -258,10 +287,9 @@ ii) Status
        should register for the event and then check the target's status.
 
     held metadata root:
-       The location, in sectors, of the metadata root that has been
+       The location, in blocks, of the metadata root that has been
        'held' for userspace read access.  '-' indicates there is no
-       held root.  This feature is not yet implemented so '-' is
-       always returned.
+       held root.
 
     discard_passdown|no_discard_passdown
        Whether or not discards are actually being passed down to the
index 10378cc48374cf8ffde068d4ce329ce5b5cbb205..04356f5bc3afbb8c91332aa1077a344526862af0 100644 (file)
@@ -353,6 +353,7 @@ Your cooperation is appreciated.
                133 = /dev/exttrp       External device trap
                134 = /dev/apm_bios     Advanced Power Management BIOS
                135 = /dev/rtc          Real Time Clock
+               137 = /dev/vhci         Bluetooth virtual HCI driver
                139 = /dev/openprom     SPARC OpenBoot PROM
                140 = /dev/relay8       Berkshire Products Octal relay card
                141 = /dev/relay16      Berkshire Products ISO-16 relay card
index 34dc40cffdfd8bfa316d55c2db5cc7a49fc1e999..af9b4a0d902b3f7a182864b02dbfec13fb6c2cba 100644 (file)
@@ -91,7 +91,7 @@ Boards:
   compatible = "ti,omap3-beagle", "ti,omap3"
 
 - OMAP3 Tobi with Overo : Commercial expansion board with daughter board
-  compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"
+  compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3"
 
 - OMAP4 SDP : Software Development Board
   compatible = "ti,omap4-sdp", "ti,omap4430"
index a6a352c2771e74da0064ec9ce93a87c44ce2fe07..5992dceec7af7d1e9d1ac8f329b831d48e409d87 100644 (file)
@@ -21,9 +21,9 @@ Required Properties:
     must appear in the same order as the output clocks.
   - #clock-cells: Must be 1
   - clock-output-names: The name of the clocks as free-form strings
-  - renesas,indices: Indices of the gate clocks into the group (0 to 31)
+  - renesas,clock-indices: Indices of the gate clocks into the group (0 to 31)
 
-The clocks, clock-output-names and renesas,indices properties contain one
+The clocks, clock-output-names and renesas,clock-indices properties contain one
 entry per gate clock. The MSTP groups are sparsely populated. Unimplemented
 gate clocks must not be declared.
 
index 68b83ecc385007216d391f1a0edf06527dad5fb9..ee9be9961524cdcb45a0c43890064e8483702323 100644 (file)
@@ -1,12 +1,16 @@
 * Freescale Smart Direct Memory Access (SDMA) Controller for i.MX
 
 Required properties:
-- compatible : Should be "fsl,imx31-sdma", "fsl,imx31-to1-sdma",
-  "fsl,imx31-to2-sdma", "fsl,imx35-sdma", "fsl,imx35-to1-sdma",
-  "fsl,imx35-to2-sdma", "fsl,imx51-sdma", "fsl,imx53-sdma" or
-  "fsl,imx6q-sdma". The -to variants should be preferred since they
-  allow to determnine the correct ROM script addresses needed for
-  the driver to work without additional firmware.
+- compatible : Should be one of
+      "fsl,imx25-sdma"
+      "fsl,imx31-sdma", "fsl,imx31-to1-sdma", "fsl,imx31-to2-sdma"
+      "fsl,imx35-sdma", "fsl,imx35-to1-sdma", "fsl,imx35-to2-sdma"
+      "fsl,imx51-sdma"
+      "fsl,imx53-sdma"
+      "fsl,imx6q-sdma"
+  The -to variants should be preferred since they allow to determnine the
+  correct ROM script addresses needed for the driver to work without additional
+  firmware.
 - reg : Should contain SDMA registers location and length
 - interrupts : Should contain SDMA interrupt
 - #dma-cells : Must be <3>.
diff --git a/Documentation/devicetree/bindings/net/altera_tse.txt b/Documentation/devicetree/bindings/net/altera_tse.txt
new file mode 100644 (file)
index 0000000..a706297
--- /dev/null
@@ -0,0 +1,114 @@
+* Altera Triple-Speed Ethernet MAC driver (TSE)
+
+Required properties:
+- compatible: Should be "altr,tse-1.0" for legacy SGDMA based TSE, and should
+               be "altr,tse-msgdma-1.0" for the preferred MSGDMA based TSE.
+               ALTR is supported for legacy device trees, but is deprecated.
+               altr should be used for all new designs.
+- reg: Address and length of the register set for the device. It contains
+  the information of registers in the same order as described by reg-names
+- reg-names: Should contain the reg names
+  "control_port": MAC configuration space region
+  "tx_csr":       xDMA Tx dispatcher control and status space region
+  "tx_desc":      MSGDMA Tx dispatcher descriptor space region
+  "rx_csr" :      xDMA Rx dispatcher control and status space region
+  "rx_desc":      MSGDMA Rx dispatcher descriptor space region
+  "rx_resp":      MSGDMA Rx dispatcher response space region
+  "s1":                  SGDMA descriptor memory
+- interrupts: Should contain the TSE interrupts and it's mode.
+- interrupt-names: Should contain the interrupt names
+  "rx_irq":       xDMA Rx dispatcher interrupt
+  "tx_irq":       xDMA Tx dispatcher interrupt
+- rx-fifo-depth: MAC receive FIFO buffer depth in bytes
+- tx-fifo-depth: MAC transmit FIFO buffer depth in bytes
+- phy-mode: See ethernet.txt in the same directory.
+- phy-handle: See ethernet.txt in the same directory.
+- phy-addr: See ethernet.txt in the same directory. A configuration should
+               include phy-handle or phy-addr.
+- altr,has-supplementary-unicast:
+               If present, TSE supports additional unicast addresses.
+               Otherwise additional unicast addresses are not supported.
+- altr,has-hash-multicast-filter:
+               If present, TSE supports a hash based multicast filter.
+               Otherwise, hash-based multicast filtering is not supported.
+
+- mdio device tree subnode: When the TSE has a phy connected to its local
+               mdio, there must be device tree subnode with the following
+               required properties:
+
+       - compatible: Must be "altr,tse-mdio".
+       - #address-cells: Must be <1>.
+       - #size-cells: Must be <0>.
+
+       For each phy on the mdio bus, there must be a node with the following
+       fields:
+
+       - reg: phy id used to communicate to phy.
+       - device_type: Must be "ethernet-phy".
+
+Optional properties:
+- local-mac-address: See ethernet.txt in the same directory.
+- max-frame-size: See ethernet.txt in the same directory.
+
+Example:
+
+       tse_sub_0_eth_tse_0: ethernet@0x1,00000000 {
+               compatible = "altr,tse-msgdma-1.0";
+               reg =   <0x00000001 0x00000000 0x00000400>,
+                       <0x00000001 0x00000460 0x00000020>,
+                       <0x00000001 0x00000480 0x00000020>,
+                       <0x00000001 0x000004A0 0x00000008>,
+                       <0x00000001 0x00000400 0x00000020>,
+                       <0x00000001 0x00000420 0x00000020>;
+               reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
+               interrupt-parent = <&hps_0_arm_gic_0>;
+               interrupts = <0 41 4>, <0 40 4>;
+               interrupt-names = "rx_irq", "tx_irq";
+               rx-fifo-depth = <2048>;
+               tx-fifo-depth = <2048>;
+               address-bits = <48>;
+               max-frame-size = <1500>;
+               local-mac-address = [ 00 00 00 00 00 00 ];
+               phy-mode = "gmii";
+               altr,has-supplementary-unicast;
+               altr,has-hash-multicast-filter;
+               phy-handle = <&phy0>;
+               mdio {
+                       compatible = "altr,tse-mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       phy0: ethernet-phy@0 {
+                               reg = <0x0>;
+                               device_type = "ethernet-phy";
+                       };
+
+                       phy1: ethernet-phy@1 {
+                               reg = <0x1>;
+                               device_type = "ethernet-phy";
+                       };
+
+               };
+       };
+
+       tse_sub_1_eth_tse_0: ethernet@0x1,00001000 {
+               compatible = "altr,tse-msgdma-1.0";
+               reg =   <0x00000001 0x00001000 0x00000400>,
+                       <0x00000001 0x00001460 0x00000020>,
+                       <0x00000001 0x00001480 0x00000020>,
+                       <0x00000001 0x000014A0 0x00000008>,
+                       <0x00000001 0x00001400 0x00000020>,
+                       <0x00000001 0x00001420 0x00000020>;
+               reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
+               interrupt-parent = <&hps_0_arm_gic_0>;
+               interrupts = <0 43 4>, <0 42 4>;
+               interrupt-names = "rx_irq", "tx_irq";
+               rx-fifo-depth = <2048>;
+               tx-fifo-depth = <2048>;
+               address-bits = <48>;
+               max-frame-size = <1500>;
+               local-mac-address = [ 00 00 00 00 00 00 ];
+               phy-mode = "gmii";
+               altr,has-supplementary-unicast;
+               altr,has-hash-multicast-filter;
+               phy-handle = <&phy1>;
+       };
diff --git a/Documentation/devicetree/bindings/net/opencores-ethoc.txt b/Documentation/devicetree/bindings/net/opencores-ethoc.txt
new file mode 100644 (file)
index 0000000..2dc127c
--- /dev/null
@@ -0,0 +1,22 @@
+* OpenCores MAC 10/100 Mbps
+
+Required properties:
+- compatible: Should be "opencores,ethoc".
+- reg: two memory regions (address and length),
+  first region is for the device registers and descriptor rings,
+  second is for the device packet memory.
+- interrupts: interrupt for the device.
+
+Optional properties:
+- clocks: phandle to refer to the clk used as per
+  Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Examples:
+
+       enet0: ethoc@fd030000 {
+               compatible = "opencores,ethoc";
+               reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
+               interrupts = <1>;
+               local-mac-address = [00 50 c2 13 6f 00];
+               clocks = <&osc>;
+        };
diff --git a/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt b/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
new file mode 100644 (file)
index 0000000..189ae5c
--- /dev/null
@@ -0,0 +1,39 @@
+* Texas Instruments wl1251 wireless lan controller
+
+The wl1251 chip can be connected via SPI or via SDIO. This
+document describes the binding for the SPI connected chip.
+
+Required properties:
+- compatible :        Should be "ti,wl1251"
+- reg :               Chip select address of device
+- spi-max-frequency : Maximum SPI clocking speed of device in Hz
+- interrupts :        Should contain interrupt line
+- interrupt-parent :  Should be the phandle for the interrupt controller
+                      that services interrupts for this device
+- vio-supply :        phandle to regulator providing VIO
+- ti,power-gpio :     GPIO connected to chip's PMEN pin
+
+Optional properties:
+- ti,wl1251-has-eeprom : boolean, the wl1251 has an eeprom connected, which
+                         provides configuration data (calibration, MAC, ...)
+- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
+  for optional SPI connection related properties,
+
+Examples:
+
+&spi1 {
+       wl1251@0 {
+               compatible = "ti,wl1251";
+
+               reg = <0>;
+               spi-max-frequency = <48000000>;
+               spi-cpol;
+               spi-cpha;
+
+               interrupt-parent = <&gpio2>;
+               interrupts = <10 IRQ_TYPE_NONE>; /* gpio line 42 */
+
+               vio-supply = <&vio>;
+               ti,power-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */
+       };
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt
new file mode 100644 (file)
index 0000000..c119deb
--- /dev/null
@@ -0,0 +1,461 @@
+Broadcom BCM281xx Pin Controller
+
+This is a pin controller for the Broadcom BCM281xx SoC family, which includes
+BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
+
+=== Pin Controller Node ===
+
+Required Properties:
+
+- compatible:  Must be "brcm,bcm11351-pinctrl"
+- reg:         Base address of the PAD Controller register block and the size
+               of the block.
+
+For example, the following is the bare minimum node:
+
+       pinctrl@35004800 {
+               compatible = "brcm,bcm11351-pinctrl";
+               reg = <0x35004800 0x430>;
+       };
+
+As a pin controller device, in addition to the required properties, this node
+should also contain the pin configuration nodes that client devices reference,
+if any.
+
+=== Pin Configuration Node ===
+
+Each pin configuration node is a sub-node of the pin controller node and is a
+container of an arbitrary number of subnodes, called pin group nodes in this
+document.
+
+Please refer to the pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the definition of a
+"pin configuration node".
+
+=== Pin Group Node ===
+
+A pin group node specifies the desired pin mux and/or pin configuration for an
+arbitrary number of pins.  The name of the pin group node is optional and not
+used.
+
+A pin group node only affects the properties specified in the node, and has no
+effect on any properties that are omitted.
+
+The pin group node accepts a subset of the generic pin config properties. For
+details generic pin config properties, please refer to pinctrl-bindings.txt
+and <include/linux/pinctrl/pinconfig-generic.h>.
+
+Each pin controlled by this pin controller belong to one of three types:
+Standard, I2C, and HDMI.  Each type accepts a different set of pin config
+properties.  A list of pins and their types is provided below.
+
+Required Properties (applicable to all pins):
+
+- pins:                Multiple strings.  Specifies the name(s) of one or more pins to
+               be configured by this node.
+
+Optional Properties (for standard pins):
+
+- function:                    String. Specifies the pin mux selection. Values
+                               must be one of: "alt1", "alt2", "alt3", "alt4"
+- input-schmitt-enable:                No arguments. Enable schmitt-trigger mode.
+- input-schmitt-disable:       No arguments. Disable schmitt-trigger mode.
+- bias-pull-up:                        No arguments. Pull up on pin.
+- bias-pull-down:              No arguments. Pull down on pin.
+- bias-disable:                        No arguments. Disable pin bias.
+- slew-rate:                   Integer. Meaning depends on configured pin mux:
+                               *_SCL or *_SDA:
+                                       0: Standard(100kbps)& Fast(400kbps) mode
+                                       1: Highspeed (3.4Mbps) mode
+                               IC_DM or IC_DP:
+                                       0: normal slew rate
+                                       1: fast slew rate
+                               Otherwise:
+                                       0: fast slew rate
+                                       1: normal slew rate
+- input-enable:                        No arguements. Enable input (does not affect
+                               output.)
+- input-disable:               No arguements. Disable input (does not affect
+                               output.)
+- drive-strength:              Integer. Drive strength in mA.  Valid values are
+                               2, 4, 6, 8, 10, 12, 14, 16 mA.
+
+Optional Properties (for I2C pins):
+
+- function:                    String. Specifies the pin mux selection. Values
+                               must be one of: "alt1", "alt2", "alt3", "alt4"
+- bias-pull-up:                        Integer. Pull up strength in Ohm. There are 3
+                               pull-up resisitors (1.2k, 1.8k, 2.7k) available
+                               in parallel for I2C pins, so the valid values
+                               are: 568, 720, 831, 1080, 1200, 1800, 2700 Ohm.
+- bias-disable:                        No arguments. Disable pin bias.
+- slew-rate:                   Integer. Meaning depends on configured pin mux:
+                               *_SCL or *_SDA:
+                                       0: Standard(100kbps)& Fast(400kbps) mode
+                                       1: Highspeed (3.4Mbps) mode
+                               IC_DM or IC_DP:
+                                       0: normal slew rate
+                                       1: fast slew rate
+                               Otherwise:
+                                       0: fast slew rate
+                                       1: normal slew rate
+- input-enable:                        No arguements. Enable input (does not affect
+                               output.)
+- input-disable:               No arguements. Disable input (does not affect
+                               output.)
+
+Optional Properties (for HDMI pins):
+
+- function:                    String. Specifies the pin mux selection. Values
+                               must be one of: "alt1", "alt2", "alt3", "alt4"
+- slew-rate:                   Integer. Controls slew rate.
+                                       0: Standard(100kbps)& Fast(400kbps) mode
+                                       1: Highspeed (3.4Mbps) mode
+- input-enable:                        No arguements. Enable input (does not affect
+                               output.)
+- input-disable:               No arguements. Disable input (does not affect
+                               output.)
+
+Example:
+// pin controller node
+pinctrl@35004800 {
+       compatible = "brcmbcm11351-pinctrl";
+       reg = <0x35004800 0x430>;
+
+       // pin configuration node
+       dev_a_default: dev_a_active {
+               //group node defining 1 standard pin
+               grp_1 {
+                       pins            = "std_pin1";
+                       function        = "alt1";
+                       input-schmitt-enable;
+                       bias-disable;
+                       slew-rate       = <1>;
+                       drive-strength  = <4>;
+               };
+
+               // group node defining 2 I2C pins
+               grp_2 {
+                       pins            = "i2c_pin1", "i2c_pin2";
+                       function        = "alt2";
+                       bias-pull-up    = <720>;
+                       input-enable;
+               };
+
+               // group node defining 2 HDMI pins
+               grp_3 {
+                       pins            = "hdmi_pin1", "hdmi_pin2";
+                       function        = "alt3";
+                       slew-rate       = <1>;
+               };
+
+               // other pin group nodes
+               ...
+       };
+
+       // other pin configuration nodes
+       ...
+};
+
+In the example above, "dev_a_active" is a pin configuration node with a number
+of sub-nodes.  In the pin group node "grp_1", one pin, "std_pin1", is defined in
+the "pins" property.  Thus, the remaining properties in the "grp_1" node applies
+only to this pin, including the following settings:
+ - setting pinmux to "alt1"
+ - enabling schmitt-trigger (hystersis) mode
+ - disabling pin bias
+ - setting the slew-rate to 1
+ - setting the drive strength to 4 mA
+Note that neither "input-enable" nor "input-disable" was specified - the pinctrl
+subsystem will therefore leave this property unchanged from whatever state it
+was in before applying these changes.
+
+The "pins" property in the pin group node "grp_2" specifies two pins -
+"i2c_pin1" and "i2c_pin2"; the remaining properties in this pin group node,
+therefore, applies to both of these pins.  The properties include:
+ - setting pinmux to "alt2"
+ - setting pull-up resistance to 720 Ohm (ie. enabling 1.2k and 1.8k resistors
+   in parallel)
+ - enabling both pins' input
+"slew-rate" is not specified in this pin group node, so the slew-rate for these
+pins are left as-is.
+
+Finally, "grp_3" defines two HDMI pins.  The following properties are applied to
+both pins:
+ - setting pinmux to "alt3"
+ - setting slew-rate to 1; for HDMI pins, this corresponds to the 3.4 Mbps
+   Highspeed mode
+The input is neither enabled or disabled, and is left untouched.
+
+=== Pin Names and Type ===
+
+The following are valid pin names and their pin types:
+
+       "adcsync",              Standard
+       "bat_rm",               Standard
+       "bsc1_scl",             I2C
+       "bsc1_sda",             I2C
+       "bsc2_scl",             I2C
+       "bsc2_sda",             I2C
+       "classgpwr",            Standard
+       "clk_cx8",              Standard
+       "clkout_0",             Standard
+       "clkout_1",             Standard
+       "clkout_2",             Standard
+       "clkout_3",             Standard
+       "clkreq_in_0",          Standard
+       "clkreq_in_1",          Standard
+       "cws_sys_req1",         Standard
+       "cws_sys_req2",         Standard
+       "cws_sys_req3",         Standard
+       "digmic1_clk",          Standard
+       "digmic1_dq",           Standard
+       "digmic2_clk",          Standard
+       "digmic2_dq",           Standard
+       "gpen13",               Standard
+       "gpen14",               Standard
+       "gpen15",               Standard
+       "gpio00",               Standard
+       "gpio01",               Standard
+       "gpio02",               Standard
+       "gpio03",               Standard
+       "gpio04",               Standard
+       "gpio05",               Standard
+       "gpio06",               Standard
+       "gpio07",               Standard
+       "gpio08",               Standard
+       "gpio09",               Standard
+       "gpio10",               Standard
+       "gpio11",               Standard
+       "gpio12",               Standard
+       "gpio13",               Standard
+       "gpio14",               Standard
+       "gps_pablank",          Standard
+       "gps_tmark",            Standard
+       "hdmi_scl",             HDMI
+       "hdmi_sda",             HDMI
+       "ic_dm",                Standard
+       "ic_dp",                Standard
+       "kp_col_ip_0",          Standard
+       "kp_col_ip_1",          Standard
+       "kp_col_ip_2",          Standard
+       "kp_col_ip_3",          Standard
+       "kp_row_op_0",          Standard
+       "kp_row_op_1",          Standard
+       "kp_row_op_2",          Standard
+       "kp_row_op_3",          Standard
+       "lcd_b_0",              Standard
+       "lcd_b_1",              Standard
+       "lcd_b_2",              Standard
+       "lcd_b_3",              Standard
+       "lcd_b_4",              Standard
+       "lcd_b_5",              Standard
+       "lcd_b_6",              Standard
+       "lcd_b_7",              Standard
+       "lcd_g_0",              Standard
+       "lcd_g_1",              Standard
+       "lcd_g_2",              Standard
+       "lcd_g_3",              Standard
+       "lcd_g_4",              Standard
+       "lcd_g_5",              Standard
+       "lcd_g_6",              Standard
+       "lcd_g_7",              Standard
+       "lcd_hsync",            Standard
+       "lcd_oe",               Standard
+       "lcd_pclk",             Standard
+       "lcd_r_0",              Standard
+       "lcd_r_1",              Standard
+       "lcd_r_2",              Standard
+       "lcd_r_3",              Standard
+       "lcd_r_4",              Standard
+       "lcd_r_5",              Standard
+       "lcd_r_6",              Standard
+       "lcd_r_7",              Standard
+       "lcd_vsync",            Standard
+       "mdmgpio0",             Standard
+       "mdmgpio1",             Standard
+       "mdmgpio2",             Standard
+       "mdmgpio3",             Standard
+       "mdmgpio4",             Standard
+       "mdmgpio5",             Standard
+       "mdmgpio6",             Standard
+       "mdmgpio7",             Standard
+       "mdmgpio8",             Standard
+       "mphi_data_0",          Standard
+       "mphi_data_1",          Standard
+       "mphi_data_2",          Standard
+       "mphi_data_3",          Standard
+       "mphi_data_4",          Standard
+       "mphi_data_5",          Standard
+       "mphi_data_6",          Standard
+       "mphi_data_7",          Standard
+       "mphi_data_8",          Standard
+       "mphi_data_9",          Standard
+       "mphi_data_10",         Standard
+       "mphi_data_11",         Standard
+       "mphi_data_12",         Standard
+       "mphi_data_13",         Standard
+       "mphi_data_14",         Standard
+       "mphi_data_15",         Standard
+       "mphi_ha0",             Standard
+       "mphi_hat0",            Standard
+       "mphi_hat1",            Standard
+       "mphi_hce0_n",          Standard
+       "mphi_hce1_n",          Standard
+       "mphi_hrd_n",           Standard
+       "mphi_hwr_n",           Standard
+       "mphi_run0",            Standard
+       "mphi_run1",            Standard
+       "mtx_scan_clk",         Standard
+       "mtx_scan_data",        Standard
+       "nand_ad_0",            Standard
+       "nand_ad_1",            Standard
+       "nand_ad_2",            Standard
+       "nand_ad_3",            Standard
+       "nand_ad_4",            Standard
+       "nand_ad_5",            Standard
+       "nand_ad_6",            Standard
+       "nand_ad_7",            Standard
+       "nand_ale",             Standard
+       "nand_cen_0",           Standard
+       "nand_cen_1",           Standard
+       "nand_cle",             Standard
+       "nand_oen",             Standard
+       "nand_rdy_0",           Standard
+       "nand_rdy_1",           Standard
+       "nand_wen",             Standard
+       "nand_wp",              Standard
+       "pc1",                  Standard
+       "pc2",                  Standard
+       "pmu_int",              Standard
+       "pmu_scl",              I2C
+       "pmu_sda",              I2C
+       "rfst2g_mtsloten3g",    Standard
+       "rgmii_0_rx_ctl",       Standard
+       "rgmii_0_rxc",          Standard
+       "rgmii_0_rxd_0",        Standard
+       "rgmii_0_rxd_1",        Standard
+       "rgmii_0_rxd_2",        Standard
+       "rgmii_0_rxd_3",        Standard
+       "rgmii_0_tx_ctl",       Standard
+       "rgmii_0_txc",          Standard
+       "rgmii_0_txd_0",        Standard
+       "rgmii_0_txd_1",        Standard
+       "rgmii_0_txd_2",        Standard
+       "rgmii_0_txd_3",        Standard
+       "rgmii_1_rx_ctl",       Standard
+       "rgmii_1_rxc",          Standard
+       "rgmii_1_rxd_0",        Standard
+       "rgmii_1_rxd_1",        Standard
+       "rgmii_1_rxd_2",        Standard
+       "rgmii_1_rxd_3",        Standard
+       "rgmii_1_tx_ctl",       Standard
+       "rgmii_1_txc",          Standard
+       "rgmii_1_txd_0",        Standard
+       "rgmii_1_txd_1",        Standard
+       "rgmii_1_txd_2",        Standard
+       "rgmii_1_txd_3",        Standard
+       "rgmii_gpio_0",         Standard
+       "rgmii_gpio_1",         Standard
+       "rgmii_gpio_2",         Standard
+       "rgmii_gpio_3",         Standard
+       "rtxdata2g_txdata3g1",  Standard
+       "rtxen2g_txdata3g2",    Standard
+       "rxdata3g0",            Standard
+       "rxdata3g1",            Standard
+       "rxdata3g2",            Standard
+       "sdio1_clk",            Standard
+       "sdio1_cmd",            Standard
+       "sdio1_data_0",         Standard
+       "sdio1_data_1",         Standard
+       "sdio1_data_2",         Standard
+       "sdio1_data_3",         Standard
+       "sdio4_clk",            Standard
+       "sdio4_cmd",            Standard
+       "sdio4_data_0",         Standard
+       "sdio4_data_1",         Standard
+       "sdio4_data_2",         Standard
+       "sdio4_data_3",         Standard
+       "sim_clk",              Standard
+       "sim_data",             Standard
+       "sim_det",              Standard
+       "sim_resetn",           Standard
+       "sim2_clk",             Standard
+       "sim2_data",            Standard
+       "sim2_det",             Standard
+       "sim2_resetn",          Standard
+       "sri_c",                Standard
+       "sri_d",                Standard
+       "sri_e",                Standard
+       "ssp_extclk",           Standard
+       "ssp0_clk",             Standard
+       "ssp0_fs",              Standard
+       "ssp0_rxd",             Standard
+       "ssp0_txd",             Standard
+       "ssp2_clk",             Standard
+       "ssp2_fs_0",            Standard
+       "ssp2_fs_1",            Standard
+       "ssp2_fs_2",            Standard
+       "ssp2_fs_3",            Standard
+       "ssp2_rxd_0",           Standard
+       "ssp2_rxd_1",           Standard
+       "ssp2_txd_0",           Standard
+       "ssp2_txd_1",           Standard
+       "ssp3_clk",             Standard
+       "ssp3_fs",              Standard
+       "ssp3_rxd",             Standard
+       "ssp3_txd",             Standard
+       "ssp4_clk",             Standard
+       "ssp4_fs",              Standard
+       "ssp4_rxd",             Standard
+       "ssp4_txd",             Standard
+       "ssp5_clk",             Standard
+       "ssp5_fs",              Standard
+       "ssp5_rxd",             Standard
+       "ssp5_txd",             Standard
+       "ssp6_clk",             Standard
+       "ssp6_fs",              Standard
+       "ssp6_rxd",             Standard
+       "ssp6_txd",             Standard
+       "stat_1",               Standard
+       "stat_2",               Standard
+       "sysclken",             Standard
+       "traceclk",             Standard
+       "tracedt00",            Standard
+       "tracedt01",            Standard
+       "tracedt02",            Standard
+       "tracedt03",            Standard
+       "tracedt04",            Standard
+       "tracedt05",            Standard
+       "tracedt06",            Standard
+       "tracedt07",            Standard
+       "tracedt08",            Standard
+       "tracedt09",            Standard
+       "tracedt10",            Standard
+       "tracedt11",            Standard
+       "tracedt12",            Standard
+       "tracedt13",            Standard
+       "tracedt14",            Standard
+       "tracedt15",            Standard
+       "txdata3g0",            Standard
+       "txpwrind",             Standard
+       "uartb1_ucts",          Standard
+       "uartb1_urts",          Standard
+       "uartb1_urxd",          Standard
+       "uartb1_utxd",          Standard
+       "uartb2_urxd",          Standard
+       "uartb2_utxd",          Standard
+       "uartb3_ucts",          Standard
+       "uartb3_urts",          Standard
+       "uartb3_urxd",          Standard
+       "uartb3_utxd",          Standard
+       "uartb4_ucts",          Standard
+       "uartb4_urts",          Standard
+       "uartb4_urxd",          Standard
+       "uartb4_utxd",          Standard
+       "vc_cam1_scl",          I2C
+       "vc_cam1_sda",          I2C
+       "vc_cam2_scl",          I2C
+       "vc_cam2_sda",          I2C
+       "vc_cam3_scl",          I2C
+       "vc_cam3_sda",          I2C
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt
deleted file mode 100644 (file)
index 9e9e9ef..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-Broadcom Capri Pin Controller
-
-This is a pin controller for the Broadcom BCM281xx SoC family, which includes
-BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
-
-=== Pin Controller Node ===
-
-Required Properties:
-
-- compatible:  Must be "brcm,capri-pinctrl".
-- reg:         Base address of the PAD Controller register block and the size
-               of the block.
-
-For example, the following is the bare minimum node:
-
-       pinctrl@35004800 {
-               compatible = "brcm,capri-pinctrl";
-               reg = <0x35004800 0x430>;
-       };
-
-As a pin controller device, in addition to the required properties, this node
-should also contain the pin configuration nodes that client devices reference,
-if any.
-
-=== Pin Configuration Node ===
-
-Each pin configuration node is a sub-node of the pin controller node and is a
-container of an arbitrary number of subnodes, called pin group nodes in this
-document.
-
-Please refer to the pinctrl-bindings.txt in this directory for details of the
-common pinctrl bindings used by client devices, including the definition of a
-"pin configuration node".
-
-=== Pin Group Node ===
-
-A pin group node specifies the desired pin mux and/or pin configuration for an
-arbitrary number of pins.  The name of the pin group node is optional and not
-used.
-
-A pin group node only affects the properties specified in the node, and has no
-effect on any properties that are omitted.
-
-The pin group node accepts a subset of the generic pin config properties. For
-details generic pin config properties, please refer to pinctrl-bindings.txt
-and <include/linux/pinctrl/pinconfig-generic.h>.
-
-Each pin controlled by this pin controller belong to one of three types:
-Standard, I2C, and HDMI.  Each type accepts a different set of pin config
-properties.  A list of pins and their types is provided below.
-
-Required Properties (applicable to all pins):
-
-- pins:                Multiple strings.  Specifies the name(s) of one or more pins to
-               be configured by this node.
-
-Optional Properties (for standard pins):
-
-- function:                    String. Specifies the pin mux selection. Values
-                               must be one of: "alt1", "alt2", "alt3", "alt4"
-- input-schmitt-enable:                No arguments. Enable schmitt-trigger mode.
-- input-schmitt-disable:       No arguments. Disable schmitt-trigger mode.
-- bias-pull-up:                        No arguments. Pull up on pin.
-- bias-pull-down:              No arguments. Pull down on pin.
-- bias-disable:                        No arguments. Disable pin bias.
-- slew-rate:                   Integer. Meaning depends on configured pin mux:
-                               *_SCL or *_SDA:
-                                       0: Standard(100kbps)& Fast(400kbps) mode
-                                       1: Highspeed (3.4Mbps) mode
-                               IC_DM or IC_DP:
-                                       0: normal slew rate
-                                       1: fast slew rate
-                               Otherwise:
-                                       0: fast slew rate
-                                       1: normal slew rate
-- input-enable:                        No arguements. Enable input (does not affect
-                               output.)
-- input-disable:               No arguements. Disable input (does not affect
-                               output.)
-- drive-strength:              Integer. Drive strength in mA.  Valid values are
-                               2, 4, 6, 8, 10, 12, 14, 16 mA.
-
-Optional Properties (for I2C pins):
-
-- function:                    String. Specifies the pin mux selection. Values
-                               must be one of: "alt1", "alt2", "alt3", "alt4"
-- bias-pull-up:                        Integer. Pull up strength in Ohm. There are 3
-                               pull-up resisitors (1.2k, 1.8k, 2.7k) available
-                               in parallel for I2C pins, so the valid values
-                               are: 568, 720, 831, 1080, 1200, 1800, 2700 Ohm.
-- bias-disable:                        No arguments. Disable pin bias.
-- slew-rate:                   Integer. Meaning depends on configured pin mux:
-                               *_SCL or *_SDA:
-                                       0: Standard(100kbps)& Fast(400kbps) mode
-                                       1: Highspeed (3.4Mbps) mode
-                               IC_DM or IC_DP:
-                                       0: normal slew rate
-                                       1: fast slew rate
-                               Otherwise:
-                                       0: fast slew rate
-                                       1: normal slew rate
-- input-enable:                        No arguements. Enable input (does not affect
-                               output.)
-- input-disable:               No arguements. Disable input (does not affect
-                               output.)
-
-Optional Properties (for HDMI pins):
-
-- function:                    String. Specifies the pin mux selection. Values
-                               must be one of: "alt1", "alt2", "alt3", "alt4"
-- slew-rate:                   Integer. Controls slew rate.
-                                       0: Standard(100kbps)& Fast(400kbps) mode
-                                       1: Highspeed (3.4Mbps) mode
-- input-enable:                        No arguements. Enable input (does not affect
-                               output.)
-- input-disable:               No arguements. Disable input (does not affect
-                               output.)
-
-Example:
-// pin controller node
-pinctrl@35004800 {
-       compatible = "brcm,capri-pinctrl";
-       reg = <0x35004800 0x430>;
-
-       // pin configuration node
-       dev_a_default: dev_a_active {
-               //group node defining 1 standard pin
-               grp_1 {
-                       pins            = "std_pin1";
-                       function        = "alt1";
-                       input-schmitt-enable;
-                       bias-disable;
-                       slew-rate       = <1>;
-                       drive-strength  = <4>;
-               };
-
-               // group node defining 2 I2C pins
-               grp_2 {
-                       pins            = "i2c_pin1", "i2c_pin2";
-                       function        = "alt2";
-                       bias-pull-up    = <720>;
-                       input-enable;
-               };
-
-               // group node defining 2 HDMI pins
-               grp_3 {
-                       pins            = "hdmi_pin1", "hdmi_pin2";
-                       function        = "alt3";
-                       slew-rate       = <1>;
-               };
-
-               // other pin group nodes
-               ...
-       };
-
-       // other pin configuration nodes
-       ...
-};
-
-In the example above, "dev_a_active" is a pin configuration node with a number
-of sub-nodes.  In the pin group node "grp_1", one pin, "std_pin1", is defined in
-the "pins" property.  Thus, the remaining properties in the "grp_1" node applies
-only to this pin, including the following settings:
- - setting pinmux to "alt1"
- - enabling schmitt-trigger (hystersis) mode
- - disabling pin bias
- - setting the slew-rate to 1
- - setting the drive strength to 4 mA
-Note that neither "input-enable" nor "input-disable" was specified - the pinctrl
-subsystem will therefore leave this property unchanged from whatever state it
-was in before applying these changes.
-
-The "pins" property in the pin group node "grp_2" specifies two pins -
-"i2c_pin1" and "i2c_pin2"; the remaining properties in this pin group node,
-therefore, applies to both of these pins.  The properties include:
- - setting pinmux to "alt2"
- - setting pull-up resistance to 720 Ohm (ie. enabling 1.2k and 1.8k resistors
-   in parallel)
- - enabling both pins' input
-"slew-rate" is not specified in this pin group node, so the slew-rate for these
-pins are left as-is.
-
-Finally, "grp_3" defines two HDMI pins.  The following properties are applied to
-both pins:
- - setting pinmux to "alt3"
- - setting slew-rate to 1; for HDMI pins, this corresponds to the 3.4 Mbps
-   Highspeed mode
-The input is neither enabled or disabled, and is left untouched.
-
-=== Pin Names and Type ===
-
-The following are valid pin names and their pin types:
-
-       "adcsync",              Standard
-       "bat_rm",               Standard
-       "bsc1_scl",             I2C
-       "bsc1_sda",             I2C
-       "bsc2_scl",             I2C
-       "bsc2_sda",             I2C
-       "classgpwr",            Standard
-       "clk_cx8",              Standard
-       "clkout_0",             Standard
-       "clkout_1",             Standard
-       "clkout_2",             Standard
-       "clkout_3",             Standard
-       "clkreq_in_0",          Standard
-       "clkreq_in_1",          Standard
-       "cws_sys_req1",         Standard
-       "cws_sys_req2",         Standard
-       "cws_sys_req3",         Standard
-       "digmic1_clk",          Standard
-       "digmic1_dq",           Standard
-       "digmic2_clk",          Standard
-       "digmic2_dq",           Standard
-       "gpen13",               Standard
-       "gpen14",               Standard
-       "gpen15",               Standard
-       "gpio00",               Standard
-       "gpio01",               Standard
-       "gpio02",               Standard
-       "gpio03",               Standard
-       "gpio04",               Standard
-       "gpio05",               Standard
-       "gpio06",               Standard
-       "gpio07",               Standard
-       "gpio08",               Standard
-       "gpio09",               Standard
-       "gpio10",               Standard
-       "gpio11",               Standard
-       "gpio12",               Standard
-       "gpio13",               Standard
-       "gpio14",               Standard
-       "gps_pablank",          Standard
-       "gps_tmark",            Standard
-       "hdmi_scl",             HDMI
-       "hdmi_sda",             HDMI
-       "ic_dm",                Standard
-       "ic_dp",                Standard
-       "kp_col_ip_0",          Standard
-       "kp_col_ip_1",          Standard
-       "kp_col_ip_2",          Standard
-       "kp_col_ip_3",          Standard
-       "kp_row_op_0",          Standard
-       "kp_row_op_1",          Standard
-       "kp_row_op_2",          Standard
-       "kp_row_op_3",          Standard
-       "lcd_b_0",              Standard
-       "lcd_b_1",              Standard
-       "lcd_b_2",              Standard
-       "lcd_b_3",              Standard
-       "lcd_b_4",              Standard
-       "lcd_b_5",              Standard
-       "lcd_b_6",              Standard
-       "lcd_b_7",              Standard
-       "lcd_g_0",              Standard
-       "lcd_g_1",              Standard
-       "lcd_g_2",              Standard
-       "lcd_g_3",              Standard
-       "lcd_g_4",              Standard
-       "lcd_g_5",              Standard
-       "lcd_g_6",              Standard
-       "lcd_g_7",              Standard
-       "lcd_hsync",            Standard
-       "lcd_oe",               Standard
-       "lcd_pclk",             Standard
-       "lcd_r_0",              Standard
-       "lcd_r_1",              Standard
-       "lcd_r_2",              Standard
-       "lcd_r_3",              Standard
-       "lcd_r_4",              Standard
-       "lcd_r_5",              Standard
-       "lcd_r_6",              Standard
-       "lcd_r_7",              Standard
-       "lcd_vsync",            Standard
-       "mdmgpio0",             Standard
-       "mdmgpio1",             Standard
-       "mdmgpio2",             Standard
-       "mdmgpio3",             Standard
-       "mdmgpio4",             Standard
-       "mdmgpio5",             Standard
-       "mdmgpio6",             Standard
-       "mdmgpio7",             Standard
-       "mdmgpio8",             Standard
-       "mphi_data_0",          Standard
-       "mphi_data_1",          Standard
-       "mphi_data_2",          Standard
-       "mphi_data_3",          Standard
-       "mphi_data_4",          Standard
-       "mphi_data_5",          Standard
-       "mphi_data_6",          Standard
-       "mphi_data_7",          Standard
-       "mphi_data_8",          Standard
-       "mphi_data_9",          Standard
-       "mphi_data_10",         Standard
-       "mphi_data_11",         Standard
-       "mphi_data_12",         Standard
-       "mphi_data_13",         Standard
-       "mphi_data_14",         Standard
-       "mphi_data_15",         Standard
-       "mphi_ha0",             Standard
-       "mphi_hat0",            Standard
-       "mphi_hat1",            Standard
-       "mphi_hce0_n",          Standard
-       "mphi_hce1_n",          Standard
-       "mphi_hrd_n",           Standard
-       "mphi_hwr_n",           Standard
-       "mphi_run0",            Standard
-       "mphi_run1",            Standard
-       "mtx_scan_clk",         Standard
-       "mtx_scan_data",        Standard
-       "nand_ad_0",            Standard
-       "nand_ad_1",            Standard
-       "nand_ad_2",            Standard
-       "nand_ad_3",            Standard
-       "nand_ad_4",            Standard
-       "nand_ad_5",            Standard
-       "nand_ad_6",            Standard
-       "nand_ad_7",            Standard
-       "nand_ale",             Standard
-       "nand_cen_0",           Standard
-       "nand_cen_1",           Standard
-       "nand_cle",             Standard
-       "nand_oen",             Standard
-       "nand_rdy_0",           Standard
-       "nand_rdy_1",           Standard
-       "nand_wen",             Standard
-       "nand_wp",              Standard
-       "pc1",                  Standard
-       "pc2",                  Standard
-       "pmu_int",              Standard
-       "pmu_scl",              I2C
-       "pmu_sda",              I2C
-       "rfst2g_mtsloten3g",    Standard
-       "rgmii_0_rx_ctl",       Standard
-       "rgmii_0_rxc",          Standard
-       "rgmii_0_rxd_0",        Standard
-       "rgmii_0_rxd_1",        Standard
-       "rgmii_0_rxd_2",        Standard
-       "rgmii_0_rxd_3",        Standard
-       "rgmii_0_tx_ctl",       Standard
-       "rgmii_0_txc",          Standard
-       "rgmii_0_txd_0",        Standard
-       "rgmii_0_txd_1",        Standard
-       "rgmii_0_txd_2",        Standard
-       "rgmii_0_txd_3",        Standard
-       "rgmii_1_rx_ctl",       Standard
-       "rgmii_1_rxc",          Standard
-       "rgmii_1_rxd_0",        Standard
-       "rgmii_1_rxd_1",        Standard
-       "rgmii_1_rxd_2",        Standard
-       "rgmii_1_rxd_3",        Standard
-       "rgmii_1_tx_ctl",       Standard
-       "rgmii_1_txc",          Standard
-       "rgmii_1_txd_0",        Standard
-       "rgmii_1_txd_1",        Standard
-       "rgmii_1_txd_2",        Standard
-       "rgmii_1_txd_3",        Standard
-       "rgmii_gpio_0",         Standard
-       "rgmii_gpio_1",         Standard
-       "rgmii_gpio_2",         Standard
-       "rgmii_gpio_3",         Standard
-       "rtxdata2g_txdata3g1",  Standard
-       "rtxen2g_txdata3g2",    Standard
-       "rxdata3g0",            Standard
-       "rxdata3g1",            Standard
-       "rxdata3g2",            Standard
-       "sdio1_clk",            Standard
-       "sdio1_cmd",            Standard
-       "sdio1_data_0",         Standard
-       "sdio1_data_1",         Standard
-       "sdio1_data_2",         Standard
-       "sdio1_data_3",         Standard
-       "sdio4_clk",            Standard
-       "sdio4_cmd",            Standard
-       "sdio4_data_0",         Standard
-       "sdio4_data_1",         Standard
-       "sdio4_data_2",         Standard
-       "sdio4_data_3",         Standard
-       "sim_clk",              Standard
-       "sim_data",             Standard
-       "sim_det",              Standard
-       "sim_resetn",           Standard
-       "sim2_clk",             Standard
-       "sim2_data",            Standard
-       "sim2_det",             Standard
-       "sim2_resetn",          Standard
-       "sri_c",                Standard
-       "sri_d",                Standard
-       "sri_e",                Standard
-       "ssp_extclk",           Standard
-       "ssp0_clk",             Standard
-       "ssp0_fs",              Standard
-       "ssp0_rxd",             Standard
-       "ssp0_txd",             Standard
-       "ssp2_clk",             Standard
-       "ssp2_fs_0",            Standard
-       "ssp2_fs_1",            Standard
-       "ssp2_fs_2",            Standard
-       "ssp2_fs_3",            Standard
-       "ssp2_rxd_0",           Standard
-       "ssp2_rxd_1",           Standard
-       "ssp2_txd_0",           Standard
-       "ssp2_txd_1",           Standard
-       "ssp3_clk",             Standard
-       "ssp3_fs",              Standard
-       "ssp3_rxd",             Standard
-       "ssp3_txd",             Standard
-       "ssp4_clk",             Standard
-       "ssp4_fs",              Standard
-       "ssp4_rxd",             Standard
-       "ssp4_txd",             Standard
-       "ssp5_clk",             Standard
-       "ssp5_fs",              Standard
-       "ssp5_rxd",             Standard
-       "ssp5_txd",             Standard
-       "ssp6_clk",             Standard
-       "ssp6_fs",              Standard
-       "ssp6_rxd",             Standard
-       "ssp6_txd",             Standard
-       "stat_1",               Standard
-       "stat_2",               Standard
-       "sysclken",             Standard
-       "traceclk",             Standard
-       "tracedt00",            Standard
-       "tracedt01",            Standard
-       "tracedt02",            Standard
-       "tracedt03",            Standard
-       "tracedt04",            Standard
-       "tracedt05",            Standard
-       "tracedt06",            Standard
-       "tracedt07",            Standard
-       "tracedt08",            Standard
-       "tracedt09",            Standard
-       "tracedt10",            Standard
-       "tracedt11",            Standard
-       "tracedt12",            Standard
-       "tracedt13",            Standard
-       "tracedt14",            Standard
-       "tracedt15",            Standard
-       "txdata3g0",            Standard
-       "txpwrind",             Standard
-       "uartb1_ucts",          Standard
-       "uartb1_urts",          Standard
-       "uartb1_urxd",          Standard
-       "uartb1_utxd",          Standard
-       "uartb2_urxd",          Standard
-       "uartb2_utxd",          Standard
-       "uartb3_ucts",          Standard
-       "uartb3_urts",          Standard
-       "uartb3_urxd",          Standard
-       "uartb3_utxd",          Standard
-       "uartb4_ucts",          Standard
-       "uartb4_urts",          Standard
-       "uartb4_urxd",          Standard
-       "uartb4_utxd",          Standard
-       "vc_cam1_scl",          I2C
-       "vc_cam1_sda",          I2C
-       "vc_cam2_scl",          I2C
-       "vc_cam2_sda",          I2C
-       "vc_cam3_scl",          I2C
-       "vc_cam3_sda",          I2C
diff --git a/Documentation/networking/altera_tse.txt b/Documentation/networking/altera_tse.txt
new file mode 100644 (file)
index 0000000..3f24df8
--- /dev/null
@@ -0,0 +1,263 @@
+       Altera Triple-Speed Ethernet MAC driver
+
+Copyright (C) 2008-2014 Altera Corporation
+
+This is the driver for the Altera Triple-Speed Ethernet (TSE) controllers
+using the SGDMA and MSGDMA soft DMA IP components. The driver uses the
+platform bus to obtain component resources. The designs used to test this
+driver were built for a Cyclone(R) V SOC FPGA board, a Cyclone(R) V FPGA board,
+and tested with ARM and NIOS processor hosts seperately. The anticipated use
+cases are simple communications between an embedded system and an external peer
+for status and simple configuration of the embedded system.
+
+For more information visit www.altera.com and www.rocketboards.org. Support
+forums for the driver may be found on www.rocketboards.org, and a design used
+to test this driver may be found there as well. Support is also available from
+the maintainer of this driver, found in MAINTAINERS.
+
+The Triple-Speed Ethernet, SGDMA, and MSGDMA components are all soft IP
+components that can be assembled and built into an FPGA using the Altera
+Quartus toolchain. Quartus 13.1 and 14.0 were used to build the design that
+this driver was tested against. The sopc2dts tool is used to create the
+device tree for the driver, and may be found at rocketboards.org.
+
+The driver probe function examines the device tree and determines if the
+Triple-Speed Ethernet instance is using an SGDMA or MSGDMA component. The
+probe function then installs the appropriate set of DMA routines to
+initialize, setup transmits, receives, and interrupt handling primitives for
+the respective configurations.
+
+The SGDMA component is to be deprecated in the near future (over the next 1-2
+years as of this writing in early 2014) in favor of the MSGDMA component.
+SGDMA support is included for existing designs and reference in case a
+developer wishes to support their own soft DMA logic and driver support. Any
+new designs should not use the SGDMA.
+
+The SGDMA supports only a single transmit or receive operation at a time, and
+therefore will not perform as well compared to the MSGDMA soft IP. Please
+visit www.altera.com for known, documented SGDMA errata.
+
+Scatter-gather DMA is not supported by the SGDMA or MSGDMA at this time.
+Scatter-gather DMA will be added to a future maintenance update to this
+driver.
+
+Jumbo frames are not supported at this time.
+
+The driver limits PHY operations to 10/100Mbps, and has not yet been fully
+tested for 1Gbps. This support will be added in a future maintenance update.
+
+1) Kernel Configuration
+The kernel configuration option is ALTERA_TSE:
+ Device Drivers ---> Network device support ---> Ethernet driver support --->
+ Altera Triple-Speed Ethernet MAC support (ALTERA_TSE)
+
+2) Driver parameters list:
+       debug: message level (0: no output, 16: all);
+       dma_rx_num: Number of descriptors in the RX list (default is 64);
+       dma_tx_num: Number of descriptors in the TX list (default is 64).
+
+3) Command line options
+Driver parameters can be also passed in command line by using:
+       altera_tse=dma_rx_num:128,dma_tx_num:512
+
+4) Driver information and notes
+
+4.1) Transmit process
+When the driver's transmit routine is called by the kernel, it sets up a
+transmit descriptor by calling the underlying DMA transmit routine (SGDMA or
+MSGDMA), and initites a transmit operation. Once the transmit is complete, an
+interrupt is driven by the transmit DMA logic. The driver handles the transmit
+completion in the context of the interrupt handling chain by recycling
+resource required to send and track the requested transmit operation.
+
+4.2) Receive process
+The driver will post receive buffers to the receive DMA logic during driver
+intialization. Receive buffers may or may not be queued depending upon the
+underlying DMA logic (MSGDMA is able queue receive buffers, SGDMA is not able
+to queue receive buffers to the SGDMA receive logic). When a packet is
+received, the DMA logic generates an interrupt. The driver handles a receive
+interrupt by obtaining the DMA receive logic status, reaping receive
+completions until no more receive completions are available.
+
+4.3) Interrupt Mitigation
+The driver is able to mitigate the number of its DMA interrupts
+using NAPI for receive operations. Interrupt mitigation is not yet supported
+for transmit operations, but will be added in a future maintenance release.
+
+4.4) Ethtool support
+Ethtool is supported. Driver statistics and internal errors can be taken using:
+ethtool -S ethX command. It is possible to dump registers etc.
+
+4.5) PHY Support
+The driver is compatible with PAL to work with PHY and GPHY devices.
+
+4.7) List of source files:
+ o Kconfig
+ o Makefile
+ o altera_tse_main.c: main network device driver
+ o altera_tse_ethtool.c: ethtool support
+ o altera_tse.h: private driver structure and common definitions
+ o altera_msgdma.h: MSGDMA implementation function definitions
+ o altera_sgdma.h: SGDMA implementation function definitions
+ o altera_msgdma.c: MSGDMA implementation
+ o altera_sgdma.c: SGDMA implementation
+ o altera_sgdmahw.h: SGDMA register and descriptor definitions
+ o altera_msgdmahw.h: MSGDMA register and descriptor definitions
+ o altera_utils.c: Driver utility functions
+ o altera_utils.h: Driver utility function definitions
+
+5) Debug Information
+
+The driver exports debug information such as internal statistics,
+debug information, MAC and DMA registers etc.
+
+A user may use the ethtool support to get statistics:
+e.g. using: ethtool -S ethX (that shows the statistics counters)
+or sees the MAC registers: e.g. using: ethtool -d ethX
+
+The developer can also use the "debug" module parameter to get
+further debug information.
+
+6) Statistics Support
+
+The controller and driver support a mix of IEEE standard defined statistics,
+RFC defined statistics, and driver or Altera defined statistics. The four
+specifications containing the standard definitions for these statistics are
+as follows:
+
+ o IEEE 802.3-2012 - IEEE Standard for Ethernet.
+ o RFC 2863 found at http://www.rfc-editor.org/rfc/rfc2863.txt.
+ o RFC 2819 found at http://www.rfc-editor.org/rfc/rfc2819.txt.
+ o Altera Triple Speed Ethernet User Guide, found at http://www.altera.com
+
+The statistics supported by the TSE and the device driver are as follows:
+
+"tx_packets" is equivalent to aFramesTransmittedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.2. This statistics is the count of frames that are successfully
+transmitted.
+
+"rx_packets" is equivalent to aFramesReceivedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.5. This statistic is the count of frames that are successfully
+received. This count does not include any error packets such as CRC errors,
+length errors, or alignment errors.
+
+"rx_crc_errors" is equivalent to aFrameCheckSequenceErrors defined in IEEE
+802.3-2012, Section 5.2.2.1.6. This statistic is the count of frames that are
+an integral number of bytes in length and do not pass the CRC test as the frame
+is received.
+
+"rx_align_errors" is equivalent to aAlignmentErrors defined in IEEE 802.3-2012,
+Section 5.2.2.1.7. This statistic is the count of frames that are not an
+integral number of bytes in length and do not pass the CRC test as the frame is
+received.
+
+"tx_bytes" is equivalent to aOctetsTransmittedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.8. This statistic is the count of data and pad bytes
+successfully transmitted from the interface.
+
+"rx_bytes" is equivalent to aOctetsReceivedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.14. This statistic is the count of data and pad bytes
+successfully received by the controller.
+
+"tx_pause" is equivalent to aPAUSEMACCtrlFramesTransmitted defined in IEEE
+802.3-2012, Section 30.3.4.2. This statistic is a count of PAUSE frames
+transmitted from the network controller.
+
+"rx_pause" is equivalent to aPAUSEMACCtrlFramesReceived defined in IEEE
+802.3-2012, Section 30.3.4.3. This statistic is a count of PAUSE frames
+received by the network controller.
+
+"rx_errors" is equivalent to ifInErrors defined in RFC 2863. This statistic is
+a count of the number of packets received containing errors that prevented the
+packet from being delivered to a higher level protocol.
+
+"tx_errors" is equivalent to ifOutErrors defined in RFC 2863. This statistic
+is a count of the number of packets that could not be transmitted due to errors.
+
+"rx_unicast" is equivalent to ifInUcastPkts defined in RFC 2863. This
+statistic is a count of the number of packets received that were not addressed
+to the broadcast address or a multicast group.
+
+"rx_multicast" is equivalent to ifInMulticastPkts defined in RFC 2863. This
+statistic is a count of the number of packets received that were addressed to
+a multicast address group.
+
+"rx_broadcast" is equivalent to ifInBroadcastPkts defined in RFC 2863. This
+statistic is a count of the number of packets received that were addressed to
+the broadcast address.
+
+"tx_discards" is equivalent to ifOutDiscards defined in RFC 2863. This
+statistic is the number of outbound packets not transmitted even though an
+error was not detected. An example of a reason this might occur is to free up
+internal buffer space.
+
+"tx_unicast" is equivalent to ifOutUcastPkts defined in RFC 2863. This
+statistic counts the number of packets transmitted that were not addressed to
+a multicast group or broadcast address.
+
+"tx_multicast" is equivalent to ifOutMulticastPkts defined in RFC 2863. This
+statistic counts the number of packets transmitted that were addressed to a
+multicast group.
+
+"tx_broadcast" is equivalent to ifOutBroadcastPkts defined in RFC 2863. This
+statistic counts the number of packets transmitted that were addressed to a
+broadcast address.
+
+"ether_drops" is equivalent to etherStatsDropEvents defined in RFC 2819.
+This statistic counts the number of packets dropped due to lack of internal
+controller resources.
+
+"rx_total_bytes" is equivalent to etherStatsOctets defined in RFC 2819.
+This statistic counts the total number of bytes received by the controller,
+including error and discarded packets.
+
+"rx_total_packets" is equivalent to etherStatsPkts defined in RFC 2819.
+This statistic counts the total number of packets received by the controller,
+including error, discarded, unicast, multicast, and broadcast packets.
+
+"rx_undersize" is equivalent to etherStatsUndersizePkts defined in RFC 2819.
+This statistic counts the number of correctly formed packets received less
+than 64 bytes long.
+
+"rx_oversize" is equivalent to etherStatsOversizePkts defined in RFC 2819.
+This statistic counts the number of correctly formed packets greater than 1518
+bytes long.
+
+"rx_64_bytes" is equivalent to etherStatsPkts64Octets defined in RFC 2819.
+This statistic counts the total number of packets received that were 64 octets
+in length.
+
+"rx_65_127_bytes" is equivalent to etherStatsPkts65to127Octets defined in RFC
+2819. This statistic counts the total number of packets received that were
+between 65 and 127 octets in length inclusive.
+
+"rx_128_255_bytes" is equivalent to etherStatsPkts128to255Octets defined in
+RFC 2819. This statistic is the total number of packets received that were
+between 128 and 255 octets in length inclusive.
+
+"rx_256_511_bytes" is equivalent to etherStatsPkts256to511Octets defined in
+RFC 2819. This statistic is the total number of packets received that were
+between 256 and 511 octets in length inclusive.
+
+"rx_512_1023_bytes" is equivalent to etherStatsPkts512to1023Octets defined in
+RFC 2819. This statistic is the total number of packets received that were
+between 512 and 1023 octets in length inclusive.
+
+"rx_1024_1518_bytes" is equivalent to etherStatsPkts1024to1518Octets define
+in RFC 2819. This statistic is the total number of packets received that were
+between 1024 and 1518 octets in length inclusive.
+
+"rx_gte_1519_bytes" is a statistic defined specific to the behavior of the
+Altera TSE. This statistics counts the number of received good and errored
+frames between the length of 1519 and the maximum frame length configured
+in the frm_length register. See the Altera TSE User Guide for More details.
+
+"rx_jabbers" is equivalent to etherStatsJabbers defined in RFC 2819. This
+statistic is the total number of packets received that were longer than 1518
+octets, and had either a bad CRC with an integral number of octets (CRC Error)
+or a bad CRC with a non-integral number of octets (Alignment Error).
+
+"rx_runts" is equivalent to etherStatsFragments defined in RFC 2819. This
+statistic is the total number of packets received that were less than 64 octets
+in length and had either a bad CRC with an integral number of octets (CRC
+error) or a bad CRC with a non-integral number of octets (Alignment Error).
index f3089d4235153b6fa03aaf5c8d09c81043bba996..0cbe6ec22d6ff1d6a3c739f05ae61f4dc24781ec 100644 (file)
@@ -554,12 +554,6 @@ solution for a couple of reasons:
   not specified in the struct can_frame and therefore it is only valid in
   CANFD_MTU sized CAN FD frames.
 
-  As long as the payload length is <=8 the received CAN frames from CAN FD
-  capable CAN devices can be received and read by legacy sockets too. When
-  user-generated CAN FD frames have a payload length <=8 these can be send
-  by legacy CAN network interfaces too. Sending CAN FD frames with payload
-  length > 8 to a legacy CAN network interface returns an -EMSGSIZE error.
-
   Implementation hint for new CAN applications:
 
   To build a CAN FD aware application use struct canfd_frame as basic CAN
index 4ebbd659256fbfe3cdf450bfed814066ae2df575..43d3549366a09d6cfbb7e4b284bb01d04fd314a0 100644 (file)
@@ -36,54 +36,6 @@ Default Value: 0
 This parameter adds support for SR-IOV.  It causes the driver to spawn up to
 max_vfs worth of virtual function.
 
-QueuePairs
-----------
-Valid Range:  0-1
-Default Value:  1 (TX and RX will be paired onto one interrupt vector)
-
-If set to 0, when MSI-X is enabled, the TX and RX will attempt to occupy
-separate vectors.
-
-This option can be overridden to 1 if there are not sufficient interrupts
-available.  This can occur if any combination of RSS, VMDQ, and max_vfs
-results in more than 4 queues being used.
-
-Node
-----
-Valid Range:   0-n
-Default Value: -1 (off)
-
-  0 - n: where n is the number of the NUMA node that should be used to
-         allocate memory for this adapter port.
-  -1: uses the driver default of allocating memory on whichever processor is
-      running insmod/modprobe.
-
-  The Node parameter will allow you to pick which NUMA node you want to have
-  the adapter allocate memory from.  All driver structures, in-memory queues,
-  and receive buffers will be allocated on the node specified.  This parameter
-  is only useful when interrupt affinity is specified, otherwise some portion
-  of the time the interrupt could run on a different core than the memory is
-  allocated on, causing slower memory access and impacting throughput, CPU, or
-  both.
-
-EEE
----
-Valid Range:  0-1
-Default Value: 1 (enabled)
-
-  A link between two EEE-compliant devices will result in periodic bursts of
-  data followed by long periods where in the link is in an idle state. This Low
-  Power Idle (LPI) state is supported in both 1Gbps and 100Mbps link speeds.
-  NOTE: EEE support requires autonegotiation.
-
-DMAC
-----
-Valid Range: 0-1
-Default Value: 1 (enabled)
-  Enables or disables DMA Coalescing feature.
-
-
-
 Additional Configurations
 =========================
 
index 1404674c0a0282af7d077cf55a5da076875bd2ed..6fea79efb4cbfd31cc1d0155aef320b94b89da9e 100644 (file)
@@ -453,7 +453,7 @@ TP_STATUS_COPY        : This flag indicates that the frame (and associated
                         enabled previously with setsockopt() and 
                         the PACKET_COPY_THRESH option. 
 
-                        The number of frames than can be buffered to 
+                        The number of frames that can be buffered to
                         be read with recvfrom is limited like a normal socket.
                         See the SO_RCVBUF option in the socket (7) man page.
 
index b89bc82eed4656430ab2d4d4a6454d08ac44624f..16a924c486bf3adb856efc2a2bec72b90311f2ff 100644 (file)
@@ -27,6 +27,8 @@ Contents of this document:
 
  (*) AF_RXRPC kernel interface.
 
+ (*) Configurable parameters.
+
 
 ========
 OVERVIEW
@@ -864,3 +866,82 @@ The kernel interface functions are as follows:
 
      This is used to allocate a null RxRPC key that can be used to indicate
      anonymous security for a particular domain.
+
+
+=======================
+CONFIGURABLE PARAMETERS
+=======================
+
+The RxRPC protocol driver has a number of configurable parameters that can be
+adjusted through sysctls in /proc/net/rxrpc/:
+
+ (*) req_ack_delay
+
+     The amount of time in milliseconds after receiving a packet with the
+     request-ack flag set before we honour the flag and actually send the
+     requested ack.
+
+     Usually the other side won't stop sending packets until the advertised
+     reception window is full (to a maximum of 255 packets), so delaying the
+     ACK permits several packets to be ACK'd in one go.
+
+ (*) soft_ack_delay
+
+     The amount of time in milliseconds after receiving a new packet before we
+     generate a soft-ACK to tell the sender that it doesn't need to resend.
+
+ (*) idle_ack_delay
+
+     The amount of time in milliseconds after all the packets currently in the
+     received queue have been consumed before we generate a hard-ACK to tell
+     the sender it can free its buffers, assuming no other reason occurs that
+     we would send an ACK.
+
+ (*) resend_timeout
+
+     The amount of time in milliseconds after transmitting a packet before we
+     transmit it again, assuming no ACK is received from the receiver telling
+     us they got it.
+
+ (*) max_call_lifetime
+
+     The maximum amount of time in seconds that a call may be in progress
+     before we preemptively kill it.
+
+ (*) dead_call_expiry
+
+     The amount of time in seconds before we remove a dead call from the call
+     list.  Dead calls are kept around for a little while for the purpose of
+     repeating ACK and ABORT packets.
+
+ (*) connection_expiry
+
+     The amount of time in seconds after a connection was last used before we
+     remove it from the connection list.  Whilst a connection is in existence,
+     it serves as a placeholder for negotiated security; when it is deleted,
+     the security must be renegotiated.
+
+ (*) transport_expiry
+
+     The amount of time in seconds after a transport was last used before we
+     remove it from the transport list.  Whilst a transport is in existence, it
+     serves to anchor the peer data and keeps the connection ID counter.
+
+ (*) rxrpc_rx_window_size
+
+     The size of the receive window in packets.  This is the maximum number of
+     unconsumed received packets we're willing to hold in memory for any
+     particular call.
+
+ (*) rxrpc_rx_mtu
+
+     The maximum packet MTU size that we're willing to receive in bytes.  This
+     indicates to the peer whether we're willing to accept jumbo packets.
+
+ (*) rxrpc_rx_jumbo_max
+
+     The maximum number of packets that we're willing to accept in a jumbo
+     packet.  Non-terminal packets in a jumbo packet must contain a four byte
+     header plus exactly 1412 bytes of data.  The terminal packet must contain
+     a four byte header plus any amount of data.  In any event, a jumbo packet
+     may not exceed rxrpc_rx_mtu in size.
index 661d3c316a17721d787a8a601f3e9c8356e957be..048c92b487f6a50b552cf12d47abe4212ba66f36 100644 (file)
@@ -21,26 +21,38 @@ has such a feature).
 
 SO_TIMESTAMPING:
 
-Instructs the socket layer which kind of information is wanted. The
-parameter is an integer with some of the following bits set. Setting
-other bits is an error and doesn't change the current state.
-
-SOF_TIMESTAMPING_TX_HARDWARE:  try to obtain send time stamp in hardware
-SOF_TIMESTAMPING_TX_SOFTWARE:  if SOF_TIMESTAMPING_TX_HARDWARE is off or
-                               fails, then do it in software
-SOF_TIMESTAMPING_RX_HARDWARE:  return the original, unmodified time stamp
-                               as generated by the hardware
-SOF_TIMESTAMPING_RX_SOFTWARE:  if SOF_TIMESTAMPING_RX_HARDWARE is off or
-                               fails, then do it in software
-SOF_TIMESTAMPING_RAW_HARDWARE: return original raw hardware time stamp
-SOF_TIMESTAMPING_SYS_HARDWARE: return hardware time stamp transformed to
-                               the system time base
-SOF_TIMESTAMPING_SOFTWARE:     return system time stamp generated in
-                               software
-
-SOF_TIMESTAMPING_TX/RX determine how time stamps are generated.
-SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the
-following control message:
+Instructs the socket layer which kind of information should be collected
+and/or reported.  The parameter is an integer with some of the following
+bits set. Setting other bits is an error and doesn't change the current
+state.
+
+Four of the bits are requests to the stack to try to generate
+timestamps.  Any combination of them is valid.
+
+SOF_TIMESTAMPING_TX_HARDWARE:  try to obtain send time stamps in hardware
+SOF_TIMESTAMPING_TX_SOFTWARE:  try to obtain send time stamps in software
+SOF_TIMESTAMPING_RX_HARDWARE:  try to obtain receive time stamps in hardware
+SOF_TIMESTAMPING_RX_SOFTWARE:  try to obtain receive time stamps in software
+
+The other three bits control which timestamps will be reported in a
+generated control message.  If none of these bits are set or if none of
+the set bits correspond to data that is available, then the control
+message will not be generated:
+
+SOF_TIMESTAMPING_SOFTWARE:     report systime if available
+SOF_TIMESTAMPING_SYS_HARDWARE: report hwtimetrans if available
+SOF_TIMESTAMPING_RAW_HARDWARE: report hwtimeraw if available
+
+It is worth noting that timestamps may be collected for reasons other
+than being requested by a particular socket with
+SOF_TIMESTAMPING_[TR]X_(HARD|SOFT)WARE.  For example, most drivers that
+can generate hardware receive timestamps ignore
+SOF_TIMESTAMPING_RX_HARDWARE.  It is still a good idea to set that flag
+in case future drivers pay attention.
+
+If timestamps are reported, they will appear in a control message with
+cmsg_level==SOL_SOCKET, cmsg_type==SO_TIMESTAMPING, and a payload like
+this:
 
 struct scm_timestamping {
        struct timespec systime;
index ebd298e00f4493c3797e7852e6f5425d22275639..9109eab722f5d5d5fa92bee20bed666d631c35ad 100644 (file)
@@ -73,7 +73,8 @@ Descriptions of section entries:
        L: Mailing list that is relevant to this area
        W: Web-page with status/info
        Q: Patchwork web based patch tracking system site
-       T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit, topgit.
+       T: SCM tree type and location.
+          Type is one of: git, hg, quilt, stgit, topgit
        S: Status, one of the following:
           Supported:   Someone is actually paid to look after this.
           Maintained:  Someone actually looks after it.
@@ -473,7 +474,7 @@ F:  net/rxrpc/af_rxrpc.c
 
 AGPGART DRIVER
 M:     David Airlie <airlied@linux.ie>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+T:     git git://people.freedesktop.org/~airlied/linux (part of drm maint)
 S:     Maintained
 F:     drivers/char/agp/
 F:     include/linux/agp*
@@ -535,10 +536,17 @@ S:        Odd Fixes
 L:     linux-alpha@vger.kernel.org
 F:     arch/alpha/
 
+ALTERA TRIPLE SPEED ETHERNET DRIVER
+M:     Vince Bridgers <vbridgers2013@gmail.com
+L:     netdev@vger.kernel.org
+L:     nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/net/ethernet/altera/
+
 ALTERA UART/JTAG UART SERIAL DRIVERS
 M:     Tobias Klauser <tklauser@distanz.ch>
 L:     linux-serial@vger.kernel.org
-L:     nios2-dev@sopc.et.ntust.edu.tw (moderated for non-subscribers)
+L:     nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/tty/serial/altera_uart.c
 F:     drivers/tty/serial/altera_jtaguart.c
@@ -1612,11 +1620,11 @@ S:      Maintained
 F:     drivers/net/wireless/atmel*
 
 ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
-M:      Bradley Grove <linuxdrivers@attotech.com>
-L:      linux-scsi@vger.kernel.org
-W:      http://www.attotech.com
-S:      Supported
-F:      drivers/scsi/esas2r
+M:     Bradley Grove <linuxdrivers@attotech.com>
+L:     linux-scsi@vger.kernel.org
+W:     http://www.attotech.com
+S:     Supported
+F:     drivers/scsi/esas2r
 
 AUDIT SUBSYSTEM
 M:     Eric Paris <eparis@redhat.com>
@@ -1737,6 +1745,7 @@ F:        include/uapi/linux/bfs_fs.h
 BLACKFIN ARCHITECTURE
 M:     Steven Miao <realmz6@gmail.com>
 L:     adi-buildroot-devel@lists.sourceforge.net
+T:     git git://git.code.sf.net/p/adi-linux/code
 W:     http://blackfin.uclinux.org
 S:     Supported
 F:     arch/blackfin/
@@ -1866,6 +1875,7 @@ F:        drivers/net/ethernet/broadcom/bnx2x/
 
 BROADCOM BCM281XX/BCM11XXX ARM ARCHITECTURE
 M:     Christian Daudt <bcm@fixthebug.org>
+M:     Matt Porter <mporter@linaro.org>
 L:     bcm-kernel-feedback-list@broadcom.com
 T:     git git://git.github.com/broadcom/bcm11351
 S:     Maintained
@@ -2164,7 +2174,7 @@ F:        Documentation/zh_CN/
 
 CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
 M:     Peter Chen <Peter.Chen@freescale.com>
-T:     git://github.com/hzpeterchen/linux-usb.git
+T:     git git://github.com/hzpeterchen/linux-usb.git
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/chipidea/
@@ -2184,9 +2194,9 @@ S:        Supported
 F:     drivers/net/ethernet/cisco/enic/
 
 CISCO VIC LOW LATENCY NIC DRIVER
-M:      Upinder Malhi <umalhi@cisco.com>
-S:      Supported
-F:      drivers/infiniband/hw/usnic
+M:     Upinder Malhi <umalhi@cisco.com>
+S:     Supported
+F:     drivers/infiniband/hw/usnic
 
 CIRRUS LOGIC EP93XX ETHERNET DRIVER
 M:     Hartley Sweeten <hsweeten@visionengravers.com>
@@ -2383,20 +2393,20 @@ F:      drivers/cpufreq/arm_big_little.c
 F:     drivers/cpufreq/arm_big_little_dt.c
 
 CPUIDLE DRIVER - ARM BIG LITTLE
-M:      Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-M:      Daniel Lezcano <daniel.lezcano@linaro.org>
-L:      linux-pm@vger.kernel.org
-L:      linux-arm-kernel@lists.infradead.org
-T:      git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
-S:      Maintained
-F:      drivers/cpuidle/cpuidle-big_little.c
+M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+M:     Daniel Lezcano <daniel.lezcano@linaro.org>
+L:     linux-pm@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+S:     Maintained
+F:     drivers/cpuidle/cpuidle-big_little.c
 
 CPUIDLE DRIVERS
 M:     Rafael J. Wysocki <rjw@rjwysocki.net>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
-T:     git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
 F:     drivers/cpuidle/*
 F:     include/linux/cpuidle.h
 
@@ -2414,8 +2424,10 @@ F:       tools/power/cpupower/
 
 CPUSETS
 M:     Li Zefan <lizefan@huawei.com>
+L:     cgroups@vger.kernel.org
 W:     http://www.bullopensource.org/cpuset/
 W:     http://oss.sgi.com/projects/cpusets/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
 S:     Maintained
 F:     Documentation/cgroups/cpusets.txt
 F:     include/linux/cpuset.h
@@ -2461,9 +2473,9 @@ S:        Maintained
 F:     sound/pci/cs5535audio/
 
 CW1200 WLAN driver
-M:     Solomon Peachy <pizza@shaftnet.org>
-S:     Maintained
-F:     drivers/net/wireless/cw1200/
+M:     Solomon Peachy <pizza@shaftnet.org>
+S:     Maintained
+F:     drivers/net/wireless/cw1200/
 
 CX18 VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
@@ -2614,9 +2626,9 @@ DC395x SCSI driver
 M:     Oliver Neukum <oliver@neukum.org>
 M:     Ali Akcaagac <aliakc@web.de>
 M:     Jamie Lenehan <lenehan@twibble.org>
-W:     http://twibble.org/dist/dc395x/
 L:     dc395x@twibble.org
-L:     http://lists.twibble.org/mailman/listinfo/dc395x/
+W:     http://twibble.org/dist/dc395x/
+W:     http://lists.twibble.org/mailman/listinfo/dc395x/
 S:     Maintained
 F:     Documentation/scsi/dc395x.txt
 F:     drivers/scsi/dc395x.*
@@ -2851,12 +2863,22 @@ F:      lib/kobj*
 DRM DRIVERS
 M:     David Airlie <airlied@linux.ie>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+T:     git git://people.freedesktop.org/~airlied/linux
 S:     Maintained
 F:     drivers/gpu/drm/
 F:     include/drm/
 F:     include/uapi/drm/
 
+RADEON DRM DRIVERS
+M:     Alex Deucher <alexander.deucher@amd.com>
+M:     Christian König <christian.koenig@amd.com>
+L:     dri-devel@lists.freedesktop.org
+T:     git git://people.freedesktop.org/~agd5f/linux
+S:     Supported
+F:     drivers/gpu/drm/radeon/
+F:     include/drm/radeon*
+F:     include/uapi/drm/radeon*
+
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
 M:     Daniel Vetter <daniel.vetter@ffwll.ch>
 M:     Jani Nikula <jani.nikula@linux.intel.com>
@@ -3088,6 +3110,8 @@ F:        fs/ecryptfs/
 
 EDAC-CORE
 M:     Doug Thompson <dougthompson@xmission.com>
+M:     Borislav Petkov <bp@alien8.de>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Supported
@@ -4551,6 +4575,7 @@ F:        Documentation/networking/ixgbevf.txt
 F:     Documentation/networking/i40e.txt
 F:     Documentation/networking/i40evf.txt
 F:     drivers/net/ethernet/intel/
+F:     drivers/net/ethernet/intel/*/
 
 INTEL-MID GPIO DRIVER
 M:     David Cohen <david.a.cohen@linux.intel.com>
@@ -4907,7 +4932,7 @@ F:        drivers/staging/ktap/
 KCONFIG
 M:     "Yann E. MORIN" <yann.morin.1998@free.fr>
 L:     linux-kbuild@vger.kernel.org
-T:     git://gitorious.org/linux-kconfig/linux-kconfig
+T:     git git://gitorious.org/linux-kconfig/linux-kconfig
 S:     Maintained
 F:     Documentation/kbuild/kconfig-language.txt
 F:     scripts/kconfig/
@@ -5464,11 +5489,11 @@ S:      Maintained
 F:     drivers/media/tuners/m88ts2022*
 
 MA901 MASTERKIT USB FM RADIO DRIVER
-M:      Alexey Klimov <klimov.linux@gmail.com>
-L:      linux-media@vger.kernel.org
-T:      git git://linuxtv.org/media_tree.git
-S:      Maintained
-F:      drivers/media/radio/radio-ma901.c
+M:     Alexey Klimov <klimov.linux@gmail.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/radio/radio-ma901.c
 
 MAC80211
 M:     Johannes Berg <johannes@sipsolutions.net>
@@ -5504,6 +5529,11 @@ W:       http://www.kernel.org/doc/man-pages
 L:     linux-man@vger.kernel.org
 S:     Maintained
 
+MARVELL ARMADA DRM SUPPORT
+M:     Russell King <rmk+kernel@arm.linux.org.uk>
+S:     Maintained
+F:     drivers/gpu/drm/armada/
+
 MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
 M:     Mirko Lindner <mlindner@marvell.com>
 M:     Stephen Hemminger <stephen@networkplumber.org>
@@ -5624,7 +5654,7 @@ F:        drivers/scsi/megaraid/
 
 MELLANOX ETHERNET DRIVER (mlx4_en)
 M:     Amir Vadai <amirv@mellanox.com>
-L:     netdev@vger.kernel.org
+L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
@@ -5665,7 +5695,7 @@ F:        include/linux/mtd/
 F:     include/uapi/mtd/
 
 MEN A21 WATCHDOG DRIVER
-M:     Johannes Thumshirn <johannes.thumshirn@men.de>
+M:     Johannes Thumshirn <johannes.thumshirn@men.de>
 L:     linux-watchdog@vger.kernel.org
 S:     Supported
 F:     drivers/watchdog/mena21_wdt.c
@@ -5721,20 +5751,20 @@ L:      linux-rdma@vger.kernel.org
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-T:     git://openfabrics.org/~eli/connect-ib.git
+T:     git git://openfabrics.org/~eli/connect-ib.git
 S:     Supported
 F:     drivers/net/ethernet/mellanox/mlx5/core/
 F:     include/linux/mlx5/
 
 Mellanox MLX5 IB driver
-M:      Eli Cohen <eli@mellanox.com>
-L:      linux-rdma@vger.kernel.org
-W:      http://www.mellanox.com
-Q:      http://patchwork.kernel.org/project/linux-rdma/list/
-T:      git://openfabrics.org/~eli/connect-ib.git
-S:      Supported
-F:      include/linux/mlx5/
-F:      drivers/infiniband/hw/mlx5/
+M:     Eli Cohen <eli@mellanox.com>
+L:     linux-rdma@vger.kernel.org
+W:     http://www.mellanox.com
+Q:     http://patchwork.kernel.org/project/linux-rdma/list/
+T:     git git://openfabrics.org/~eli/connect-ib.git
+S:     Supported
+F:     include/linux/mlx5/
+F:     drivers/infiniband/hw/mlx5/
 
 MODULE SUPPORT
 M:     Rusty Russell <rusty@rustcorp.com.au>
@@ -5986,6 +6016,8 @@ F:        include/linux/netdevice.h
 F:     include/uapi/linux/in.h
 F:     include/uapi/linux/net.h
 F:     include/uapi/linux/netdevice.h
+F:     tools/net/
+F:     tools/testing/selftests/net/
 
 NETWORKING [IPv4/IPv6]
 M:     "David S. Miller" <davem@davemloft.net>
@@ -6160,6 +6192,12 @@ S:       Supported
 F:     drivers/block/nvme*
 F:     include/linux/nvme.h
 
+NXP TDA998X DRM DRIVER
+M:     Russell King <rmk+kernel@arm.linux.org.uk>
+S:     Supported
+F:     drivers/gpu/drm/i2c/tda998x_drv.c
+F:     include/drm/i2c/tda998x.h
+
 OMAP SUPPORT
 M:     Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
@@ -8442,8 +8480,8 @@ TARGET SUBSYSTEM
 M:     Nicholas A. Bellinger <nab@linux-iscsi.org>
 L:     linux-scsi@vger.kernel.org
 L:     target-devel@vger.kernel.org
-L:     http://groups.google.com/group/linux-iscsi-target-dev
 W:     http://www.linux-iscsi.org
+W:     http://groups.google.com/group/linux-iscsi-target-dev
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
 S:     Supported
 F:     drivers/target/
@@ -8684,17 +8722,17 @@ S:      Maintained
 F:     drivers/media/radio/radio-raremono.c
 
 THERMAL
-M:      Zhang Rui <rui.zhang@intel.com>
-M:      Eduardo Valentin <eduardo.valentin@ti.com>
-L:      linux-pm@vger.kernel.org
-T:      git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
-T:      git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
-Q:      https://patchwork.kernel.org/project/linux-pm/list/
-S:      Supported
-F:      drivers/thermal/
-F:      include/linux/thermal.h
-F:      include/linux/cpu_cooling.h
-F:      Documentation/devicetree/bindings/thermal/
+M:     Zhang Rui <rui.zhang@intel.com>
+M:     Eduardo Valentin <eduardo.valentin@ti.com>
+L:     linux-pm@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
+Q:     https://patchwork.kernel.org/project/linux-pm/list/
+S:     Supported
+F:     drivers/thermal/
+F:     include/linux/thermal.h
+F:     include/linux/cpu_cooling.h
+F:     Documentation/devicetree/bindings/thermal/
 
 THINGM BLINK(1) USB RGB LED DRIVER
 M:     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
@@ -9728,7 +9766,6 @@ F:        drivers/xen/*swiotlb*
 XFS FILESYSTEM
 P:     Silicon Graphics Inc
 M:     Dave Chinner <david@fromorbit.com>
-M:     Ben Myers <bpm@sgi.com>
 M:     xfs@oss.sgi.com
 L:     xfs@oss.sgi.com
 W:     http://oss.sgi.com/projects/xfs
@@ -9797,7 +9834,7 @@ ZR36067 VIDEO FOR LINUX DRIVER
 L:     mjpeg-users@lists.sourceforge.net
 L:     linux-media@vger.kernel.org
 W:     http://mjpeg.sourceforge.net/driver-zoran/
-T:     Mercurial http://linuxtv.org/hg/v4l-dvb
+T:     hg http://linuxtv.org/hg/v4l-dvb
 S:     Odd Fixes
 F:     drivers/media/pci/zoran/
 
index 893d6f0e875bf7589f5de14317c60457fd2a9513..1a2628ee5d917376f0f9262eb8c0ba4722a89775 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 14
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc6
 NAME = Shuffling Zombie Juror
 
 # *DOCUMENTATION*
@@ -605,10 +605,11 @@ endif
 ifdef CONFIG_CC_STACKPROTECTOR_REGULAR
   stackp-flag := -fstack-protector
   ifeq ($(call cc-option, $(stackp-flag)),)
-    $(warning Cannot use CONFIG_CC_STACKPROTECTOR: \
-             -fstack-protector not supported by compiler))
+    $(warning Cannot use CONFIG_CC_STACKPROTECTOR_REGULAR: \
+             -fstack-protector not supported by compiler)
   endif
-else ifdef CONFIG_CC_STACKPROTECTOR_STRONG
+else
+ifdef CONFIG_CC_STACKPROTECTOR_STRONG
   stackp-flag := -fstack-protector-strong
   ifeq ($(call cc-option, $(stackp-flag)),)
     $(warning Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: \
@@ -618,6 +619,7 @@ else
   # Force off for distro compilers that enable stack protector by default.
   stackp-flag := $(call cc-option, -fno-stack-protector)
 endif
+endif
 KBUILD_CFLAGS += $(stackp-flag)
 
 # This warning generated too much noise in a regular build.
index 6b58c1de757744feac1d0ae54ec1fdd0693fc500..400c663b21c2bf075e977a8ccf3016fb7e03b5a6 100644 (file)
@@ -282,7 +282,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
 #else
        /* if V-P const for loop, PTAG can be written once outside loop */
        if (full_page_op)
-               write_aux_reg(ARC_REG_DC_PTAG, paddr);
+               write_aux_reg(aux_tag, paddr);
 #endif
 
        while (num_lines-- > 0) {
@@ -296,7 +296,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
                write_aux_reg(aux_cmd, vaddr);
                vaddr += L1_CACHE_BYTES;
 #else
-               write_aux_reg(aux, paddr);
+               write_aux_reg(aux_cmd, paddr);
                paddr += L1_CACHE_BYTES;
 #endif
        }
index e254198177914ca13050f37519a6ca43e0da596d..15949459611f194376dafcdebaf569f8ef141dc5 100644 (file)
@@ -1578,6 +1578,7 @@ config BL_SWITCHER_DUMMY_IF
 
 choice
        prompt "Memory split"
+       depends on MMU
        default VMSPLIT_3G
        help
          Select the desired split between kernel and user memory.
@@ -1595,6 +1596,7 @@ endchoice
 
 config PAGE_OFFSET
        hex
+       default PHYS_OFFSET if !MMU
        default 0x40000000 if VMSPLIT_1G
        default 0x80000000 if VMSPLIT_2G
        default 0xC0000000
@@ -1903,6 +1905,7 @@ config XEN
        depends on ARM && AEABI && OF
        depends on CPU_V7 && !CPU_V6
        depends on !GENERIC_ATOMIC64
+       depends on MMU
        select ARM_PSCI
        select SWIOTLB_XEN
        select ARCH_DMA_ADDR_T_64BIT
index 47279aa96a6a48fd1945ae9faa7584d49f24a355..0714e0334e33c9790b221d03859574b2f4e774ad 100644 (file)
@@ -1,4 +1,5 @@
 ashldi3.S
+bswapsdi2.S
 font.c
 lib1funcs.S
 hyp-stub.S
index 6d1e43d461871abdb0c94234da68ce21e67492b1..032030361bef2448ce84075212615d58c469cb8b 100644 (file)
@@ -209,7 +209,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
        omap3-n900.dtb \
        omap3-n9.dtb \
        omap3-n950.dtb \
-       omap3-tobi.dtb \
+       omap3-overo-tobi.dtb \
+       omap3-overo-storm-tobi.dtb \
        omap3-gta04.dtb \
        omap3-igep0020.dtb \
        omap3-igep0030.dtb \
index 4718ec4a4dbfef5e2a7273726cb6a8f0750623e3..486880b7483134c88f8638a6e7fb4cc98518e7e3 100644 (file)
                ti,model = "AM335x-EVMSK";
                ti,audio-codec = <&tlv320aic3106>;
                ti,mcasp-controller = <&mcasp1>;
-               ti,codec-clock-rate = <24576000>;
+               ti,codec-clock-rate = <24000000>;
                ti,audio-routing =
                        "Headphone Jack",       "HPLOUT",
                        "Headphone Jack",       "HPROUT";
                >;
        };
 
+       mmc1_pins: pinmux_mmc1_pins {
+               pinctrl-single,pins = <
+                       0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+               >;
+       };
+
        mcasp1_pins: mcasp1_pins {
                pinctrl-single,pins = <
                        0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
        status = "okay";
        vmmc-supply = <&vmmc_reg>;
        bus-width = <4>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pins>;
+       cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
 };
 
 &sham {
index 66609684d41b59ef701530fd2076553ffc4e9b6b..9480cf891f8cd0ce475d87cf2eed904a6a740eb7 100644 (file)
@@ -23,6 +23,7 @@
                gpio0 = &gpio0;
                gpio1 = &gpio1;
                gpio2 = &gpio2;
+               eth3 = &eth3;
        };
 
        cpus {
                                interrupts = <91>;
                        };
 
-                       ethernet@34000 {
+                       eth3: ethernet@34000 {
                                compatible = "marvell,armada-370-neta";
                                reg = <0x34000 0x4000>;
                                interrupts = <14>;
index e491b82f8d67099ce25b4d1f08cdc6777bf55d7f..792fde1b7f752a93ffa42f2e5f8c7083dc1bb55c 100644 (file)
        };
 
        pinctrl@35004800 {
-               compatible = "brcm,capri-pinctrl";
+               compatible = "brcm,bcm11351-pinctrl";
                reg = <0x35004800 0x430>;
        };
 
index 2b76524f4aa74ee475d7e027f24683097ef4770f..187fd46b7b5ef018c2985e7db5298784338f0507 100644 (file)
                                #clock-cells = <1>;
                        };
 
-                       pmu_intc: pmu-interrupt-ctrl@d0050 {
-                               compatible = "marvell,dove-pmu-intc";
-                               interrupt-controller;
-                               #interrupt-cells = <1>;
-                               reg = <0xd0050 0x8>;
-                               interrupts = <33>;
-                               marvell,#interrupts = <7>;
-                       };
-
                        pinctrl: pin-ctrl@d0200 {
                                compatible = "marvell,dove-pinctrl";
                                reg = <0xd0200 0x10>;
                        rtc: real-time-clock@d8500 {
                                compatible = "marvell,orion-rtc";
                                reg = <0xd8500 0x20>;
-                               interrupt-parent = <&pmu_intc>;
-                               interrupts = <5>;
                        };
 
                        gpio2: gpio-ctrl@e8400 {
index 2363593e1050b7b84b4705878fc10cb653b33cca..ef58d1c24313541a068436c5e590378120c6bb3b 100644 (file)
@@ -612,7 +612,7 @@ clocks {
                compatible = "ti,keystone,psc-clock";
                clocks = <&chipclk13>;
                clock-output-names = "vcp-3";
-               reg = <0x0235000a8 0xb00>, <0x02350060 0x400>;
+               reg = <0x023500a8 0xb00>, <0x02350060 0x400>;
                reg-names = "control", "domain";
                domain-id = <24>;
        };
index b9b55c95a566c3ea6f6f21e55b787b9c31c2194f..d3b253bbc8856a9ba0a2f1810c1860f875931462 100644 (file)
@@ -13,7 +13,7 @@
 
 / {
        model = "OMAP3 GTA04";
-       compatible = "ti,omap3-gta04", "ti,omap3";
+       compatible = "ti,omap3-gta04", "ti,omap36xx", "ti,omap3";
 
        cpus {
                cpu@0 {
@@ -32,7 +32,7 @@
                aux-button {
                        label = "aux";
                        linux,code = <169>;
-                       gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
                        gpio-key,wakeup;
                };
        };
@@ -92,6 +92,8 @@
        bmp085@77 {
                compatible = "bosch,bmp085";
                reg = <0x77>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <17 IRQ_TYPE_EDGE_RISING>;
        };
 
        /* leds */
        pinctrl-names = "default";
        pinctrl-0 = <&mmc1_pins>;
        vmmc-supply = <&vmmc1>;
-       vmmc_aux-supply = <&vsim>;
        bus-width = <4>;
+       ti,non-removable;
 };
 
 &mmc2 {
index 25a2b5f652fd1949ceac364ec8a154436aba05e4..f2779ac75872a4a44e2d03402fab7b6fe1a4b66b 100644 (file)
@@ -14,7 +14,7 @@
 
 / {
        model = "IGEPv2 (TI OMAP AM/DM37x)";
-       compatible = "isee,omap3-igep0020", "ti,omap3";
+       compatible = "isee,omap3-igep0020", "ti,omap36xx", "ti,omap3";
 
        leds {
                pinctrl-names = "default";
index 145c58cfc8ac1d3c322f2a2ad44abac2734bbb30..2793749eb1ba460dcf8736fc964aef7b87b05d1a 100644 (file)
@@ -13,7 +13,7 @@
 
 / {
        model = "IGEP COM MODULE (TI OMAP AM/DM37x)";
-       compatible = "isee,omap3-igep0030", "ti,omap3";
+       compatible = "isee,omap3-igep0030", "ti,omap36xx", "ti,omap3";
 
        leds {
                pinctrl-names = "default";
index 39828ce464ee527b900ff6a2013660fe1c231822..9938b5dc1909c00f01e587f15a4a1c1d2a6bc665 100644 (file)
@@ -14,5 +14,5 @@
 
 / {
        model = "Nokia N9";
-       compatible = "nokia,omap3-n9", "ti,omap3";
+       compatible = "nokia,omap3-n9", "ti,omap36xx", "ti,omap3";
 };
index 6fc85f96353024ad61d04d74d7ca51f8afb1c7ce..0bf40c90faba626c88b539965a1f928aa09bf313 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2013 Pavel Machek <pavel@ucw.cz>
- * Copyright 2013 Aaro Koskinen <aaro.koskinen@iki.fi>
+ * Copyright (C) 2013-2014 Aaro Koskinen <aaro.koskinen@iki.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 (or later) as
@@ -13,7 +13,7 @@
 
 / {
        model = "Nokia N900";
-       compatible = "nokia,omap3-n900", "ti,omap3";
+       compatible = "nokia,omap3-n900", "ti,omap3430", "ti,omap3";
 
        cpus {
                cpu@0 {
index b076a526b99973a3489bf831e0cec5c1dcff93bb..261c5589bfa3170e76cc8f469ac1d6ca07a02765 100644 (file)
@@ -14,5 +14,5 @@
 
 / {
        model = "Nokia N950";
-       compatible = "nokia,omap3-n950", "ti,omap3";
+       compatible = "nokia,omap3-n950", "ti,omap36xx", "ti,omap3";
 };
diff --git a/arch/arm/boot/dts/omap3-overo-storm-tobi.dts b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts
new file mode 100644 (file)
index 0000000..966b5c9
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * 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.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+/dts-v1/;
+
+#include "omap36xx.dtsi"
+#include "omap3-overo-tobi-common.dtsi"
+
+/ {
+       model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Tobi";
+       compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3";
+};
+
diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
new file mode 100644 (file)
index 0000000..4edc013
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * 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.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+#include "omap3-overo.dtsi"
+
+/ {
+       leds {
+               compatible = "gpio-leds";
+               heartbeat {
+                       label = "overo:red:gpio21";
+                       gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       vddvario: regulator-vddvario {
+                 compatible = "regulator-fixed";
+                 regulator-name = "vddvario";
+                 regulator-always-on;
+       };
+
+       vdd33a: regulator-vdd33a {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd33a";
+               regulator-always-on;
+       };
+};
+
+&gpmc {
+       ranges = <5 0 0x2c000000 0x1000000>;    /* CS5 */
+
+       ethernet@5,0 {
+               compatible = "smsc,lan9221", "smsc,lan9115";
+               reg = <5 0 0xff>;
+               bank-width = <2>;
+
+               gpmc,mux-add-data;
+               gpmc,cs-on-ns = <0>;
+               gpmc,cs-rd-off-ns = <42>;
+               gpmc,cs-wr-off-ns = <36>;
+               gpmc,adv-on-ns = <6>;
+               gpmc,adv-rd-off-ns = <12>;
+               gpmc,adv-wr-off-ns = <12>;
+               gpmc,oe-on-ns = <0>;
+               gpmc,oe-off-ns = <42>;
+               gpmc,we-on-ns = <0>;
+               gpmc,we-off-ns = <36>;
+               gpmc,rd-cycle-ns = <60>;
+               gpmc,wr-cycle-ns = <54>;
+               gpmc,access-ns = <36>;
+               gpmc,page-burst-access-ns = <0>;
+               gpmc,bus-turnaround-ns = <0>;
+               gpmc,cycle2cycle-delay-ns = <0>;
+               gpmc,wr-data-mux-bus-ns = <18>;
+               gpmc,wr-access-ns = <42>;
+               gpmc,cycle2cycle-samecsen;
+               gpmc,cycle2cycle-diffcsen;
+
+               interrupt-parent = <&gpio6>;
+               interrupts = <16 IRQ_TYPE_LEVEL_LOW>;   /* GPIO 176 */
+               reg-io-width = <4>;
+       };
+};
+
+&i2c3 {
+       clock-frequency = <100000>;
+};
+
+&mmc3 {
+       status = "disabled";
+};
diff --git a/arch/arm/boot/dts/omap3-overo-tobi.dts b/arch/arm/boot/dts/omap3-overo-tobi.dts
new file mode 100644 (file)
index 0000000..de5653e
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * 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.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+/dts-v1/;
+
+#include "omap34xx.dtsi"
+#include "omap3-overo-tobi-common.dtsi"
+
+/ {
+       model = "OMAP35xx Gumstix Overo on Tobi";
+       compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3";
+};
+
index a461d2fd1fb0e81862805ccec939e1c1b3a41244..597099907f8ef77423210bcf6cb2be26f8799eb5 100644 (file)
@@ -9,9 +9,6 @@
 /*
  * The Gumstix Overo must be combined with an expansion board.
  */
-/dts-v1/;
-
-#include "omap34xx.dtsi"
 
 / {
        pwmleds {
diff --git a/arch/arm/boot/dts/omap3-tobi.dts b/arch/arm/boot/dts/omap3-tobi.dts
deleted file mode 100644 (file)
index 7e4ad2a..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
- *
- * 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.
- */
-
-/*
- * Tobi expansion board is manufactured by Gumstix Inc.
- */
-
-#include "omap3-overo.dtsi"
-
-/ {
-       model = "TI OMAP3 Gumstix Overo on Tobi";
-       compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3";
-
-       leds {
-               compatible = "gpio-leds";
-               heartbeat {
-                       label = "overo:red:gpio21";
-                       gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
-                       linux,default-trigger = "heartbeat";
-               };
-       };
-
-       vddvario: regulator-vddvario {
-                 compatible = "regulator-fixed";
-                 regulator-name = "vddvario";
-                 regulator-always-on;
-       };
-
-       vdd33a: regulator-vdd33a {
-               compatible = "regulator-fixed";
-               regulator-name = "vdd33a";
-               regulator-always-on;
-       };
-};
-
-&gpmc {
-       ranges = <5 0 0x2c000000 0x1000000>;    /* CS5 */
-
-       ethernet@5,0 {
-               compatible = "smsc,lan9221", "smsc,lan9115";
-               reg = <5 0 0xff>;
-               bank-width = <2>;
-
-               gpmc,mux-add-data;
-               gpmc,cs-on-ns = <0>;
-               gpmc,cs-rd-off-ns = <42>;
-               gpmc,cs-wr-off-ns = <36>;
-               gpmc,adv-on-ns = <6>;
-               gpmc,adv-rd-off-ns = <12>;
-               gpmc,adv-wr-off-ns = <12>;
-               gpmc,oe-on-ns = <0>;
-               gpmc,oe-off-ns = <42>;
-               gpmc,we-on-ns = <0>;
-               gpmc,we-off-ns = <36>;
-               gpmc,rd-cycle-ns = <60>;
-               gpmc,wr-cycle-ns = <54>;
-               gpmc,access-ns = <36>;
-               gpmc,page-burst-access-ns = <0>;
-               gpmc,bus-turnaround-ns = <0>;
-               gpmc,cycle2cycle-delay-ns = <0>;
-               gpmc,wr-data-mux-bus-ns = <18>;
-               gpmc,wr-access-ns = <42>;
-               gpmc,cycle2cycle-samecsen;
-               gpmc,cycle2cycle-diffcsen;
-
-               interrupt-parent = <&gpio6>;
-               interrupts = <16 IRQ_TYPE_LEVEL_LOW>;   /* GPIO 176 */
-               reg-io-width = <4>;
-       };
-};
-
-&i2c3 {
-       clock-frequency = <100000>;
-};
-
-&mmc3 {
-       status = "disabled";
-};
index 10666ca8aee1c49cd35ef7373a0298df27816ae3..d4d2763f47948b65f7f0890696699a4b2b98f245 100644 (file)
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <29>;
                };
index 64961595e8d63cafaaaf2373ce6e5a580a7e6879..79fd412005b02860c5dcb8712418273584fa3b8f 100644 (file)
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <29>;
                };
index 320335abfccd763118408f3f836c0fba39ca6f69..c463fd730c9155d8c9a491cf176a7320831e29fd 100644 (file)
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <29>;
                };
index 9ff09484847b9ca8cf0eb58ed4f6ad859f5273ad..6f25cf559ad0c99f5b376ba2a05e2e629878f35b 100644 (file)
                rtc: rtc@01c20d00 {
                        compatible = "allwinner,sun7i-a20-rtc";
                        reg = <0x01c20d00 0x20>;
-                       interrupts = <0 24 1>;
+                       interrupts = <0 24 4>;
                };
 
                sid: eeprom@01c23800 {
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <0 29 4>;
                };
                hstimer@01c60000 {
                        compatible = "allwinner,sun7i-a20-hstimer";
                        reg = <0x01c60000 0x1000>;
-                       interrupts = <0 81 1>,
-                                    <0 82 1>,
-                                    <0 83 1>,
-                                    <0 84 1>;
+                       interrupts = <0 81 4>,
+                                    <0 82 4>,
+                                    <0 83 4>,
+                                    <0 84 4>;
                        clocks = <&ahb_gates 28>;
                };
 
index 389e987ec2819e31725329102f84d6f3cecbb5cd..44ec401ec36682289d8e4afa3b9b87791cd82c73 100644 (file)
@@ -57,6 +57,8 @@
                        resets = <&tegra_car 27>;
                        reset-names = "dc";
 
+                       nvidia,head = <0>;
+
                        rgb {
                                status = "disabled";
                        };
@@ -72,6 +74,8 @@
                        resets = <&tegra_car 26>;
                        reset-names = "dc";
 
+                       nvidia,head = <1>;
+
                        rgb {
                                status = "disabled";
                        };
index 480ecda3416b841b8941105d24646f1240f5ab37..48d2a7f4d0c05e2808a5cb2150298c41c1aa3367 100644 (file)
@@ -94,6 +94,8 @@
                        resets = <&tegra_car 27>;
                        reset-names = "dc";
 
+                       nvidia,head = <0>;
+
                        rgb {
                                status = "disabled";
                        };
                        resets = <&tegra_car 26>;
                        reset-names = "dc";
 
+                       nvidia,head = <1>;
+
                        rgb {
                                status = "disabled";
                        };
index 9104224124eeaac83bcedbd0e2fb7bcb3887d631..1e156d9d0506085c4ea615ac8c7e06193573edcb 100644 (file)
@@ -28,7 +28,7 @@
        compatible = "nvidia,cardhu", "nvidia,tegra30";
 
        aliases {
-               rtc0 = "/i2c@7000d000/tps6586x@34";
+               rtc0 = "/i2c@7000d000/tps65911@2d";
                rtc1 = "/rtc@7000e000";
        };
 
index ed8e7700b46dac0ba9d5ba34754fb5f8ae3dd976..19a84e933f4eae0799fc194b386bfdc51b85b880 100644 (file)
                        resets = <&tegra_car 27>;
                        reset-names = "dc";
 
+                       nvidia,head = <0>;
+
                        rgb {
                                status = "disabled";
                        };
                        resets = <&tegra_car 26>;
                        reset-names = "dc";
 
+                       nvidia,head = <1>;
+
                        rgb {
                                status = "disabled";
                        };
diff --git a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi b/arch/arm/boot/dts/testcases/tests-interrupts.dtsi
deleted file mode 100644 (file)
index c843720..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-
-/ {
-       testcase-data {
-               interrupts {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       test_intc0: intc0 {
-                               interrupt-controller;
-                               #interrupt-cells = <1>;
-                       };
-
-                       test_intc1: intc1 {
-                               interrupt-controller;
-                               #interrupt-cells = <3>;
-                       };
-
-                       test_intc2: intc2 {
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
-
-                       test_intmap0: intmap0 {
-                               #interrupt-cells = <1>;
-                               #address-cells = <0>;
-                               interrupt-map = <1 &test_intc0 9>,
-                                               <2 &test_intc1 10 11 12>,
-                                               <3 &test_intc2 13 14>,
-                                               <4 &test_intc2 15 16>;
-                       };
-
-                       test_intmap1: intmap1 {
-                               #interrupt-cells = <2>;
-                               interrupt-map = <0x5000 1 2 &test_intc0 15>;
-                       };
-
-                       interrupts0 {
-                               interrupt-parent = <&test_intc0>;
-                               interrupts = <1>, <2>, <3>, <4>;
-                       };
-
-                       interrupts1 {
-                               interrupt-parent = <&test_intmap0>;
-                               interrupts = <1>, <2>, <3>, <4>;
-                       };
-
-                       interrupts-extended0 {
-                               reg = <0x5000 0x100>;
-                               interrupts-extended = <&test_intc0 1>,
-                                                     <&test_intc1 2 3 4>,
-                                                     <&test_intc2 5 6>,
-                                                     <&test_intmap0 1>,
-                                                     <&test_intmap0 2>,
-                                                     <&test_intmap0 3>,
-                                                     <&test_intmap1 1 2>;
-                       };
-               };
-       };
-};
diff --git a/arch/arm/boot/dts/testcases/tests-phandle.dtsi b/arch/arm/boot/dts/testcases/tests-phandle.dtsi
deleted file mode 100644 (file)
index 0007d3c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-
-/ {
-       testcase-data {
-               phandle-tests {
-                       provider0: provider0 {
-                               #phandle-cells = <0>;
-                       };
-
-                       provider1: provider1 {
-                               #phandle-cells = <1>;
-                       };
-
-                       provider2: provider2 {
-                               #phandle-cells = <2>;
-                       };
-
-                       provider3: provider3 {
-                               #phandle-cells = <3>;
-                       };
-
-                       consumer-a {
-                               phandle-list =  <&provider1 1>,
-                                               <&provider2 2 0>,
-                                               <0>,
-                                               <&provider3 4 4 3>,
-                                               <&provider2 5 100>,
-                                               <&provider0>,
-                                               <&provider1 7>;
-                               phandle-list-names = "first", "second", "third";
-
-                               phandle-list-bad-phandle = <12345678 0 0>;
-                               phandle-list-bad-args = <&provider2 1 0>,
-                                                       <&provider3 0>;
-                               empty-property;
-                               unterminated-string = [40 41 42 43];
-                       };
-               };
-       };
-};
diff --git a/arch/arm/boot/dts/testcases/tests.dtsi b/arch/arm/boot/dts/testcases/tests.dtsi
deleted file mode 100644 (file)
index 3f123ec..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/include/ "tests-phandle.dtsi"
-/include/ "tests-interrupts.dtsi"
index f43907c40c93a8cb9b101d72043fc48621e0f795..65f6577113235749c3635dc30d321fa3c775b1c0 100644 (file)
@@ -1,4 +1,4 @@
-/include/ "versatile-ab.dts"
+#include <versatile-ab.dts>
 
 / {
        model = "ARM Versatile PB";
@@ -47,4 +47,4 @@
        };
 };
 
-/include/ "testcases/tests.dtsi"
+#include <testcases.dtsi>
index 00fe9e9710fd77e4a11c4c9c8c6c03534d5e6690..27d69b558c5de2caf1be2b9ac79388ae997f562a 100644 (file)
@@ -204,7 +204,10 @@ CONFIG_MMC_BLOCK_MINORS=16
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_ONESHOT=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
index 8756e4bcdba0609ff789a4f1efaa551faa39ed98..4afb376d9c7c13d07ea81502e17ba53f0554c122 100644 (file)
  */
 #define UL(x) _AC(x, UL)
 
+/* PAGE_OFFSET - the virtual address of the start of the kernel image */
+#define PAGE_OFFSET            UL(CONFIG_PAGE_OFFSET)
+
 #ifdef CONFIG_MMU
 
 /*
- * PAGE_OFFSET - the virtual address of the start of the kernel image
  * TASK_SIZE - the maximum size of a user space task.
  * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
  */
-#define PAGE_OFFSET            UL(CONFIG_PAGE_OFFSET)
 #define TASK_SIZE              (UL(CONFIG_PAGE_OFFSET) - UL(SZ_16M))
 #define TASK_UNMAPPED_BASE     ALIGN(TASK_SIZE / 3, SZ_16M)
 
 #define END_MEM                (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE)
 #endif
 
-#ifndef PAGE_OFFSET
-#define PAGE_OFFSET            PLAT_PHYS_OFFSET
-#endif
-
 /*
  * The module can be at any place in ram in nommu mode.
  */
index 47cd974e57ea3ca0de7e9feccd9e527c2ba39f1f..c96ecacb2021222936844a4807f39ef474965879 100644 (file)
@@ -177,6 +177,18 @@ __lookup_processor_type_data:
        .long   __proc_info_end
        .size   __lookup_processor_type_data, . - __lookup_processor_type_data
 
+__error_lpae:
+#ifdef CONFIG_DEBUG_LL
+       adr     r0, str_lpae
+       bl      printascii
+       b       __error
+str_lpae: .asciz "\nError: Kernel with LPAE support, but CPU does not support LPAE.\n"
+#else
+       b       __error
+#endif
+       .align
+ENDPROC(__error_lpae)
+
 __error_p:
 #ifdef CONFIG_DEBUG_LL
        adr     r0, str_p1
index 914616e0bdcd0c0108376a9e5834e9cb73219b51..f5f381d915560818dcf0d2200731a90b0c7ae404 100644 (file)
@@ -102,7 +102,7 @@ ENTRY(stext)
        and     r3, r3, #0xf                    @ extract VMSA support
        cmp     r3, #5                          @ long-descriptor translation table format?
  THUMB( it     lo )                            @ force fixup-able long branch encoding
-       blo     __error_p                       @ only classic page table format
+       blo     __error_lpae                    @ only classic page table format
 #endif
 
 #ifndef CONFIG_XIP_KERNEL
index 1d8248ea5669fa81209b2a7a8a055b7855a8c1f3..bd18bb8b2770ced6a65e5b3ad50dd79963d49c3b 100644 (file)
@@ -878,7 +878,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
                                    unsigned long cmd,
                                    void *v)
 {
-       if (cmd == CPU_PM_EXIT) {
+       if (cmd == CPU_PM_EXIT &&
+           __hyp_get_vectors() == hyp_default_vectors) {
                cpu_init_hyp_mode(NULL);
                return NOTIFY_OK;
        }
index ddc15539bad2c5996dcd5167e694b16dbdd9488b..0d68d4073068e8ad665840b8f51319e9b2bdbd89 100644 (file)
@@ -220,6 +220,10 @@ after_vfp_restore:
  * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c).  Return values are
  * passed in r0 and r1.
  *
+ * A function pointer with a value of 0xffffffff has a special meaning,
+ * and is used to implement __hyp_get_vectors in the same way as in
+ * arch/arm/kernel/hyp_stub.S.
+ *
  * The calling convention follows the standard AAPCS:
  *   r0 - r3: caller save
  *   r12:     caller save
@@ -363,6 +367,11 @@ hyp_hvc:
 host_switch_to_hyp:
        pop     {r0, r1, r2}
 
+       /* Check for __hyp_get_vectors */
+       cmp     r0, #-1
+       mrceq   p15, 4, r0, c12, c0, 0  @ get HVBAR
+       beq     1f
+
        push    {lr}
        mrs     lr, SPSR
        push    {lr}
@@ -378,7 +387,7 @@ THUMB(      orr     lr, #1)
        pop     {lr}
        msr     SPSR_csxf, lr
        pop     {lr}
-       eret
+1:     eret
 
 guest_trap:
        load_vcpu                       @ Load VCPU pointer to r0
index befcaf5d05740c4ad1a417d8be62ddae9a38f59a..ec419649320ffe8fd6cae929d4664ae8071c9fff 100644 (file)
@@ -101,11 +101,9 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
 obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o
 obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o
 
-ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o
 # i.MX6SL reuses i.MX6Q code
 obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o headsmp.o
-endif
 
 # i.MX5 based machines
 obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o
index 59c3b9b26bb40bbabe40f471d6a420efee43a1c2..baf439dc22d8268d65bd269f508c968aae822046 100644 (file)
@@ -144,13 +144,11 @@ void imx6q_set_chicken_bit(void);
 void imx_cpu_die(unsigned int cpu);
 int imx_cpu_kill(unsigned int cpu);
 
-#ifdef CONFIG_PM
 void imx6q_pm_init(void);
 void imx6q_pm_set_ccm_base(void __iomem *base);
+#ifdef CONFIG_PM
 void imx5_pm_init(void);
 #else
-static inline void imx6q_pm_init(void) {}
-static inline void imx6q_pm_set_ccm_base(void __iomem *base) {}
 static inline void imx5_pm_init(void) {}
 #endif
 
index 91449c5cb70f46affaf85602ec8f98b6f393d10f..85089d821982193b2e2d79f5f5fbf050eefad464 100644 (file)
@@ -156,6 +156,7 @@ static struct omap_usb_config nokia770_usb_config __initdata = {
        .register_dev   = 1,
        .hmc_mode       = 16,
        .pins[0]        = 6,
+       .extcon         = "tahvo-usb",
 };
 
 #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
index e2ce4f8366a785237b8c73c7a1792f0a2cadd0a7..0af7ca02314d99aa72baefb69959ccfba3380758 100644 (file)
@@ -50,6 +50,7 @@ config SOC_OMAP5
        bool "TI OMAP5"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
+       select ARCH_HAS_OPP
        select ARM_CPU_SUSPEND if PM
        select ARM_GIC
        select CPU_V7
@@ -63,6 +64,7 @@ config SOC_AM33XX
        bool "TI AM33XX"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
+       select ARCH_HAS_OPP
        select ARM_CPU_SUSPEND if PM
        select CPU_V7
        select MULTI_IRQ_HANDLER
@@ -72,6 +74,7 @@ config SOC_AM43XX
        depends on ARCH_MULTI_V7
        select CPU_V7
        select ARCH_OMAP2PLUS
+       select ARCH_HAS_OPP
        select MULTI_IRQ_HANDLER
        select ARM_GIC
        select MACH_OMAP_GENERIC
@@ -80,6 +83,7 @@ config SOC_DRA7XX
        bool "TI DRA7XX"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
+       select ARCH_HAS_OPP
        select ARM_CPU_SUSPEND if PM
        select ARM_GIC
        select CPU_V7
@@ -268,9 +272,6 @@ config MACH_OMAP_3430SDP
        default y
        select OMAP_PACKAGE_CBB
 
-config MACH_NOKIA_N800
-       bool
-
 config MACH_NOKIA_N810
        bool
 
@@ -281,7 +282,6 @@ config MACH_NOKIA_N8X0
        bool "Nokia N800/N810"
        depends on SOC_OMAP2420
        default y
-       select MACH_NOKIA_N800
        select MACH_NOKIA_N810
        select MACH_NOKIA_N810_WIMAX
        select OMAP_PACKAGE_ZAC
index de1bc6bbe5850befb37de62465c95ba52b5a2b10..cf18340eb3bbd5ecc4655cf8c12eb54de1279f2b 100644 (file)
@@ -536,11 +536,13 @@ static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
 
 static void __init pandora_wl1251_init(void)
 {
-       struct wl12xx_platform_data pandora_wl1251_pdata;
+       struct wl1251_platform_data pandora_wl1251_pdata;
        int ret;
 
        memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata));
 
+       pandora_wl1251_pdata.power_gpio = -1;
+
        ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq");
        if (ret < 0)
                goto fail;
@@ -550,7 +552,7 @@ static void __init pandora_wl1251_init(void)
                goto fail_irq;
 
        pandora_wl1251_pdata.use_eeprom = true;
-       ret = wl12xx_set_platform_data(&pandora_wl1251_pdata);
+       ret = wl1251_set_platform_data(&pandora_wl1251_pdata);
        if (ret < 0)
                goto fail_irq;
 
index 8760bbe3baab9234da17c5a55d3126de189a5778..ddfc8df83c6a9adf2c0d128c688d16e094708ac2 100644 (file)
@@ -84,7 +84,7 @@ enum {
        RX51_SPI_MIPID,         /* LCD panel */
 };
 
-static struct wl12xx_platform_data wl1251_pdata;
+static struct wl1251_platform_data wl1251_pdata;
 static struct tsc2005_platform_data tsc2005_pdata;
 
 #if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
@@ -1173,13 +1173,7 @@ static inline void board_smc91x_init(void)
 
 #endif
 
-static void rx51_wl1251_set_power(bool enable)
-{
-       gpio_set_value(RX51_WL1251_POWER_GPIO, enable);
-}
-
 static struct gpio rx51_wl1251_gpios[] __initdata = {
-       { RX51_WL1251_POWER_GPIO, GPIOF_OUT_INIT_LOW,   "wl1251 power"  },
        { RX51_WL1251_IRQ_GPIO,   GPIOF_IN,             "wl1251 irq"    },
 };
 
@@ -1196,17 +1190,16 @@ static void __init rx51_init_wl1251(void)
        if (irq < 0)
                goto err_irq;
 
-       wl1251_pdata.set_power = rx51_wl1251_set_power;
+       wl1251_pdata.power_gpio = RX51_WL1251_POWER_GPIO;
        rx51_peripherals_spi_board_info[RX51_SPI_WL1251].irq = irq;
 
        return;
 
 err_irq:
        gpio_free(RX51_WL1251_IRQ_GPIO);
-       gpio_free(RX51_WL1251_POWER_GPIO);
 error:
        printk(KERN_ERR "wl1251 board initialisation failed\n");
-       wl1251_pdata.set_power = NULL;
+       wl1251_pdata.power_gpio = -1;
 
        /*
         * Now rx51_peripherals_spi_board_info[1].irq is zero and
index 3b05aea56d1f5636d5ff2e154513cf22349b3eec..11ed9152e665274793ee83f50881efc2d9fbdded 100644 (file)
@@ -433,7 +433,9 @@ static const struct clk_ops dpll4_m5x2_ck_ops = {
        .enable         = &omap2_dflt_clk_enable,
        .disable        = &omap2_dflt_clk_disable,
        .is_enabled     = &omap2_dflt_clk_is_enabled,
+       .set_rate       = &omap3_clkoutx2_set_rate,
        .recalc_rate    = &omap3_clkoutx2_recalc,
+       .round_rate     = &omap3_clkoutx2_round_rate,
 };
 
 static const struct clk_ops dpll4_m5x2_ck_3630_ops = {
index 4c158c838d4062e1eaee78ff770e4b9dc257146f..01fc710c81818e9d48e2b26ca8742b77b392ff1c 100644 (file)
@@ -23,6 +23,8 @@
 #include "prm.h"
 #include "clockdomain.h"
 
+#define MAX_CPUS       2
+
 /* Machine specific information */
 struct idle_statedata {
        u32 cpu_state;
@@ -48,11 +50,11 @@ static struct idle_statedata omap4_idle_data[] = {
        },
 };
 
-static struct powerdomain *mpu_pd, *cpu_pd[NR_CPUS];
-static struct clockdomain *cpu_clkdm[NR_CPUS];
+static struct powerdomain *mpu_pd, *cpu_pd[MAX_CPUS];
+static struct clockdomain *cpu_clkdm[MAX_CPUS];
 
 static atomic_t abort_barrier;
-static bool cpu_done[NR_CPUS];
+static bool cpu_done[MAX_CPUS];
 static struct idle_statedata *state_ptr = &omap4_idle_data[0];
 
 /* Private functions */
index 3185ced807c952804d50199fd3ff7bc8ea68fb8f..3c418ea54bbe1a483ddc37759f0580ca7c949dd5 100644 (file)
@@ -623,6 +623,32 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk)
 
 /* Clock control for DPLL outputs */
 
+/* Find the parent DPLL for the given clkoutx2 clock */
+static struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw)
+{
+       struct clk_hw_omap *pclk = NULL;
+       struct clk *parent;
+
+       /* Walk up the parents of clk, looking for a DPLL */
+       do {
+               do {
+                       parent = __clk_get_parent(hw->clk);
+                       hw = __clk_get_hw(parent);
+               } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
+               if (!hw)
+                       break;
+               pclk = to_clk_hw_omap(hw);
+       } while (pclk && !pclk->dpll_data);
+
+       /* clk does not have a DPLL as a parent?  error in the clock data */
+       if (!pclk) {
+               WARN_ON(1);
+               return NULL;
+       }
+
+       return pclk;
+}
+
 /**
  * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
  * @clk: DPLL output struct clk
@@ -637,27 +663,14 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
        unsigned long rate;
        u32 v;
        struct clk_hw_omap *pclk = NULL;
-       struct clk *parent;
 
        if (!parent_rate)
                return 0;
 
-       /* Walk up the parents of clk, looking for a DPLL */
-       do {
-               do {
-                       parent = __clk_get_parent(hw->clk);
-                       hw = __clk_get_hw(parent);
-               } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
-               if (!hw)
-                       break;
-               pclk = to_clk_hw_omap(hw);
-       } while (pclk && !pclk->dpll_data);
+       pclk = omap3_find_clkoutx2_dpll(hw);
 
-       /* clk does not have a DPLL as a parent?  error in the clock data */
-       if (!pclk) {
-               WARN_ON(1);
+       if (!pclk)
                return 0;
-       }
 
        dd = pclk->dpll_data;
 
@@ -672,6 +685,55 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
        return rate;
 }
 
+int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long parent_rate)
+{
+       return 0;
+}
+
+long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate)
+{
+       const struct dpll_data *dd;
+       u32 v;
+       struct clk_hw_omap *pclk = NULL;
+
+       if (!*prate)
+               return 0;
+
+       pclk = omap3_find_clkoutx2_dpll(hw);
+
+       if (!pclk)
+               return 0;
+
+       dd = pclk->dpll_data;
+
+       /* TYPE J does not have a clkoutx2 */
+       if (dd->flags & DPLL_J_TYPE) {
+               *prate = __clk_round_rate(__clk_get_parent(pclk->hw.clk), rate);
+               return *prate;
+       }
+
+       WARN_ON(!dd->enable_mask);
+
+       v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask;
+       v >>= __ffs(dd->enable_mask);
+
+       /* If in bypass, the rate is fixed to the bypass rate*/
+       if (v != OMAP3XXX_EN_DPLL_LOCKED)
+               return *prate;
+
+       if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+               unsigned long best_parent;
+
+               best_parent = (rate / 2);
+               *prate = __clk_round_rate(__clk_get_parent(hw->clk),
+                               best_parent);
+       }
+
+       return *prate * 2;
+}
+
 /* OMAP3/4 non-CORE DPLL clkops */
 const struct clk_hw_omap_ops clkhwops_omap3_dpll = {
        .allow_idle     = omap3_dpll_allow_idle,
index d24926e6340fa714cf0aeacca14a6578e5b481a4..ab43755364f5a7c06ecfc367c0f055d65876dc54 100644 (file)
@@ -1339,7 +1339,7 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
                of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#ifdef CONFIG_MTD_NAND
+#if IS_ENABLED(CONFIG_MTD_NAND)
 
 static const char * const nand_xfer_types[] = {
        [NAND_OMAP_PREFETCH_POLLED]             = "prefetch-polled",
@@ -1429,7 +1429,7 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
 }
 #endif
 
-#ifdef CONFIG_MTD_ONENAND
+#if IS_ENABLED(CONFIG_MTD_ONENAND)
 static int gpmc_probe_onenand_child(struct platform_device *pdev,
                                 struct device_node *child)
 {
index d408b15b4fbfd97ecd3d82aaa46cc86788e63a8c..af432b191255030a7c8fda2be849be0a75620482 100644 (file)
@@ -179,15 +179,6 @@ static struct map_desc omap34xx_io_desc[] __initdata = {
                .length         = L4_EMU_34XX_SIZE,
                .type           = MT_DEVICE
        },
-#if defined(CONFIG_DEBUG_LL) &&                                                        \
-       (defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3))
-       {
-               .virtual        = ZOOM_UART_VIRT,
-               .pfn            = __phys_to_pfn(ZOOM_UART_BASE),
-               .length         = SZ_1M,
-               .type           = MT_DEVICE
-       },
-#endif
 };
 #endif
 
index 42d81885c700c498babd2dd2e5d322e3af2c3f19..1f33f5db10d5a2dde0d90bd29f1eb6fce9b65995 100644 (file)
@@ -1946,30 +1946,32 @@ static int _ocp_softreset(struct omap_hwmod *oh)
        if (ret)
                goto dis_opt_clks;
 
-       _write_sysconfig(v, oh);
-       ret = _clear_softreset(oh, &v);
-       if (ret)
-               goto dis_opt_clks;
-
        _write_sysconfig(v, oh);
 
        if (oh->class->sysc->srst_udelay)
                udelay(oh->class->sysc->srst_udelay);
 
        c = _wait_softreset_complete(oh);
-       if (c == MAX_MODULE_SOFTRESET_WAIT)
+       if (c == MAX_MODULE_SOFTRESET_WAIT) {
                pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
                           oh->name, MAX_MODULE_SOFTRESET_WAIT);
-       else
+               ret = -ETIMEDOUT;
+               goto dis_opt_clks;
+       } else {
                pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
+       }
+
+       ret = _clear_softreset(oh, &v);
+       if (ret)
+               goto dis_opt_clks;
+
+       _write_sysconfig(v, oh);
 
        /*
         * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
         * _wait_target_ready() or _reset()
         */
 
-       ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
-
 dis_opt_clks:
        if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
                _disable_optional_clocks(oh);
index 18f333c440db3b72ff49577ef71d24b64dbcc916..810c205d668bfa5040ed2ad0458b412eb83b538e 100644 (file)
@@ -1365,11 +1365,10 @@ static struct omap_hwmod_class_sysconfig dra7xx_spinlock_sysc = {
        .rev_offs       = 0x0000,
        .sysc_offs      = 0x0010,
        .syss_offs      = 0x0014,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+                          SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
        .sysc_fields    = &omap_hwmod_sysc_type1,
 };
 
index 3d5b24dcd9a41e2b7f4c16052bc2d931de74a0e4..c33e07e2f0d4e3d01b9e58e6347d4ca42ed81a18 100644 (file)
@@ -22,6 +22,8 @@
 #include "common-board-devices.h"
 #include "dss-common.h"
 #include "control.h"
+#include "omap-secure.h"
+#include "soc.h"
 
 struct pdata_init {
        const char *compatible;
@@ -169,6 +171,22 @@ static void __init am3517_evm_legacy_init(void)
        omap_ctrl_writel(v, AM35XX_CONTROL_IP_SW_RESET);
        omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); /* OCP barrier */
 }
+
+static void __init nokia_n900_legacy_init(void)
+{
+       hsmmc2_internal_input_clk();
+
+       if (omap_type() == OMAP2_DEVICE_TYPE_SEC) {
+               if (IS_ENABLED(CONFIG_ARM_ERRATA_430973)) {
+                       pr_info("RX-51: Enabling ARM errata 430973 workaround\n");
+                       /* set IBE to 1 */
+                       rx51_secure_update_aux_cr(BIT(6), 0);
+               } else {
+                       pr_warning("RX-51: Not enabling ARM errata 430973 workaround\n");
+                       pr_warning("Thumb binaries may crash randomly without this workaround\n");
+               }
+       }
+}
 #endif /* CONFIG_ARCH_OMAP3 */
 
 #ifdef CONFIG_ARCH_OMAP4
@@ -239,6 +257,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 #endif
 #ifdef CONFIG_ARCH_OMAP3
        OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002030, "48002030.pinmux", &pcs_pdata),
+       OF_DEV_AUXDATA("ti,omap3-padconf", 0x480025a0, "480025a0.pinmux", &pcs_pdata),
        OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002a00, "48002a00.pinmux", &pcs_pdata),
        /* Only on am3517 */
        OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL),
@@ -259,7 +278,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 static struct pdata_init pdata_quirks[] __initdata = {
 #ifdef CONFIG_ARCH_OMAP3
        { "compulab,omap3-sbc-t3730", omap3_sbc_t3730_legacy_init, },
-       { "nokia,omap3-n900", hsmmc2_internal_input_clk, },
+       { "nokia,omap3-n900", nokia_n900_legacy_init, },
        { "nokia,omap3-n9", hsmmc2_internal_input_clk, },
        { "nokia,omap3-n950", hsmmc2_internal_input_clk, },
        { "isee,omap3-igep0020", omap3_igep0020_legacy_init, },
index 6334b96b4097b6977ae29047040bf6990aed06a7..280f3c58abe505c9047e6027071ec8bafd720c57 100644 (file)
@@ -183,11 +183,11 @@ void omap4_prminst_global_warm_sw_reset(void)
                                        OMAP4_PRM_RSTCTRL_OFFSET);
        v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
        omap4_prminst_write_inst_reg(v, OMAP4430_PRM_PARTITION,
-                                OMAP4430_PRM_DEVICE_INST,
+                                dev_inst,
                                 OMAP4_PRM_RSTCTRL_OFFSET);
 
        /* OCP barrier */
        v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
-                                   OMAP4430_PRM_DEVICE_INST,
+                                   dev_inst,
                                    OMAP4_PRM_RSTCTRL_OFFSET);
 }
index f70583fee59f8b61e59a1022f07b36c26fd3210c..29997bde277d1be730aa85d98a2ae17bc0bc2da5 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/reboot.h>
+#include <linux/regulator/fixed.h>
 #include <linux/regulator/max1586.h>
 #include <linux/slab.h>
 #include <linux/i2c/pxa-i2c.h>
@@ -714,6 +715,10 @@ static struct gpio global_gpios[] = {
        { GPIO56_MT9M111_nOE, GPIOF_OUT_INIT_LOW, "Camera nOE" },
 };
 
+static struct regulator_consumer_supply fixed_5v0_consumers[] = {
+       REGULATOR_SUPPLY("power", "pwm-backlight"),
+};
+
 static void __init mioa701_machine_init(void)
 {
        int rc;
@@ -753,6 +758,10 @@ static void __init mioa701_machine_init(void)
        pxa_set_i2c_info(&i2c_pdata);
        pxa27x_set_i2c_power_info(NULL);
        pxa_set_camera_info(&mioa701_pxacamera_platform_data);
+
+       regulator_register_always_on(0, "fixed-5.0V", fixed_5v0_consumers,
+                                    ARRAY_SIZE(fixed_5v0_consumers),
+                                    5000000);
 }
 
 static void mioa701_machine_exit(void)
index f33679d2d3ee0a218d280972c5f409f0b561d41b..50e1d850ee2e01d6f29ee5004af4339f40c712b0 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef __ASM_ARCH_COLLIE_H
 #define __ASM_ARCH_COLLIE_H
 
+#include "hardware.h" /* Gives GPIO_MAX */
+
 extern void locomolcd_power(int on);
 
 #define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1)
index 4ae0286b468db6209311d14d13cd9cc673fb200b..f55b05a29b55f3ed655b36b1edf1f93f85d09c9d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/cpu_pm.h>
 #include <linux/suspend.h>
 #include <linux/err.h>
+#include <linux/slab.h>
 #include <linux/clk/tegra.h>
 
 #include <asm/smp_plat.h>
index 303a285d80fd7b7d7cc4280779c343b4a3123f4a..6191603379e13cad2da1552954c3e2fb903cc241 100644 (file)
@@ -73,10 +73,20 @@ u32 tegra_uart_config[3] = {
 static void __init tegra_init_cache(void)
 {
 #ifdef CONFIG_CACHE_L2X0
+       static const struct of_device_id pl310_ids[] __initconst = {
+               { .compatible = "arm,pl310-cache",  },
+               {}
+       };
+
+       struct device_node *np;
        int ret;
        void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
        u32 aux_ctrl, cache_type;
 
+       np = of_find_matching_node(NULL, pl310_ids);
+       if (!np)
+               return;
+
        cache_type = readl(p + L2X0_CACHE_TYPE);
        aux_ctrl = (cache_type & 0x700) << (17-8);
        aux_ctrl |= 0x7C400001;
index 1a77450e728ad17cf6b8fec2beb3111a2a8bfb94..11b3914660d2a9f518f15b09028d3dad78ad07e0 100644 (file)
@@ -1358,7 +1358,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
        *handle = DMA_ERROR_CODE;
        size = PAGE_ALIGN(size);
 
-       if (gfp & GFP_ATOMIC)
+       if (!(gfp & __GFP_WAIT))
                return __iommu_alloc_atomic(dev, size, handle);
 
        /*
index 2b3a56414271e5e31323566676097b774fca9406..ef69152f9b52e473796829545bf5cf5d1e83926a 100644 (file)
@@ -264,6 +264,9 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
                        note_page(st, addr, 3, pmd_val(*pmd));
                else
                        walk_pte(st, pmd, addr);
+
+               if (SECTION_SIZE < PMD_SIZE && pmd_large(pmd[1]))
+                       note_page(st, addr + SECTION_SIZE, 3, pmd_val(pmd[1]));
        }
 }
 
index 13fb0b3efc5f7206bb8e187ea07ff6c3337ff2be..453a179469a34fd9ffa72ec723a6bada988d4e73 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef __ASM_PERCPU_H
 #define __ASM_PERCPU_H
 
+#ifdef CONFIG_SMP
+
 static inline void set_my_cpu_offset(unsigned long off)
 {
        asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory");
@@ -36,6 +38,12 @@ static inline unsigned long __my_cpu_offset(void)
 }
 #define __my_cpu_offset __my_cpu_offset()
 
+#else  /* !CONFIG_SMP */
+
+#define set_my_cpu_offset(x)   do { } while (0)
+
+#endif /* CONFIG_SMP */
+
 #include <asm-generic/percpu.h>
 
 #endif /* __ASM_PERCPU_H */
index b524dcd17243d712b4d461cf77d4dd56ed04c8bb..aa3917c8b62318aef9424735d560be305f3465d3 100644 (file)
@@ -136,11 +136,11 @@ extern struct page *empty_zero_page;
 /*
  * The following only work if pte_present(). Undefined behaviour otherwise.
  */
-#define pte_present(pte)       (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE))
-#define pte_dirty(pte)         (pte_val(pte) & PTE_DIRTY)
-#define pte_young(pte)         (pte_val(pte) & PTE_AF)
-#define pte_special(pte)       (pte_val(pte) & PTE_SPECIAL)
-#define pte_write(pte)         (pte_val(pte) & PTE_WRITE)
+#define pte_present(pte)       (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
+#define pte_dirty(pte)         (!!(pte_val(pte) & PTE_DIRTY))
+#define pte_young(pte)         (!!(pte_val(pte) & PTE_AF))
+#define pte_special(pte)       (!!(pte_val(pte) & PTE_SPECIAL))
+#define pte_write(pte)         (!!(pte_val(pte) & PTE_WRITE))
 #define pte_exec(pte)          (!(pte_val(pte) & PTE_UXN))
 
 #define pte_valid_user(pte) \
index c3b6c63ea5fb3abe0f154544aee2eb09063c0eb8..38f0558f0c0a56a7a57fe9bb12d08eb01dea7cdc 100644 (file)
@@ -48,7 +48,11 @@ int unwind_frame(struct stackframe *frame)
 
        frame->sp = fp + 0x10;
        frame->fp = *(unsigned long *)(fp);
-       frame->pc = *(unsigned long *)(fp + 8);
+       /*
+        * -4 here because we care about the PC at time of bl,
+        * not where the return will go.
+        */
+       frame->pc = *(unsigned long *)(fp + 8) - 4;
 
        return 0;
 }
index 3b47c36e10ffcdac920a08277ee9e3e1df00a211..2c56012cb2d2c8d82588063058f4444e188d13f6 100644 (file)
@@ -694,6 +694,24 @@ __hyp_panic_str:
 
        .align  2
 
+/*
+ * u64 kvm_call_hyp(void *hypfn, ...);
+ *
+ * This is not really a variadic function in the classic C-way and care must
+ * be taken when calling this to ensure parameters are passed in registers
+ * only, since the stack will change between the caller and the callee.
+ *
+ * Call the function with the first argument containing a pointer to the
+ * function you wish to call in Hyp mode, and subsequent arguments will be
+ * passed as x0, x1, and x2 (a maximum of 3 arguments in addition to the
+ * function pointer can be passed).  The function being called must be mapped
+ * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c).  Return values are
+ * passed in r0 and r1.
+ *
+ * A function pointer with a value of 0 has a special meaning, and is
+ * used to implement __hyp_get_vectors in the same way as in
+ * arch/arm64/kernel/hyp_stub.S.
+ */
 ENTRY(kvm_call_hyp)
        hvc     #0
        ret
@@ -737,7 +755,12 @@ el1_sync:                                  // Guest trapped into EL2
        pop     x2, x3
        pop     x0, x1
 
-       push    lr, xzr
+       /* Check for __hyp_get_vectors */
+       cbnz    x0, 1f
+       mrs     x0, vbar_el2
+       b       2f
+
+1:     push    lr, xzr
 
        /*
         * Compute the function address in EL2, and shuffle the parameters.
@@ -750,7 +773,7 @@ el1_sync:                                   // Guest trapped into EL2
        blr     lr
 
        pop     lr, xzr
-       eret
+2:     eret
 
 el1_trap:
        /*
index 09c5a0f5f4d1778156a5ee83715e6a2aec7f0441..86648c083bb4b1297275dc2bc4ceb3ecd949aa5b 100644 (file)
@@ -12,6 +12,7 @@
 #define _ASM_C6X_CACHE_H
 
 #include <linux/irqflags.h>
+#include <linux/init.h>
 
 /*
  * Cache line size
index 184066ceb1f6146c9254a778c8e9c7f6b9656668..053c17b3655926ed97427a927a83081ec289d224 100644 (file)
@@ -144,7 +144,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
  * definition, which doesn't have the same semantics.  We don't want to
  * use -fno-builtin, so just hide the name ffs.
  */
-#define ffs kernel_ffs
+#define ffs(x) kernel_ffs(x)
 
 #include <asm-generic/bitops/fls.h>
 #include <asm-generic/bitops/__fls.h>
index a96bcf83a735dae2f812f81e0fc54635bb3de072..20e8a9b21d7519ebf7d506e4825d83c05629ba37 100644 (file)
@@ -98,7 +98,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid)
        /* attempt to allocate a granule's worth of cached memory pages */
 
        page = alloc_pages_exact_node(nid,
-                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                IA64_GRANULE_SHIFT-PAGE_SHIFT);
        if (!page) {
                mutex_unlock(&uc_pool->add_chunk_mutex);
index 7cc8c364924dff8e8529be82406f0acfb7dfe0f2..6fb9e813a91074cb8ae41205bb8f899bcc35cf38 100644 (file)
@@ -1,4 +1,4 @@
-
+generic-y += barrier.h
 generic-y += bitsperlong.h
 generic-y += clkdev.h
 generic-y += cputime.h
@@ -6,6 +6,7 @@ generic-y += device.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ipcbuf.h
@@ -18,6 +19,7 @@ generic-y += local.h
 generic-y += mman.h
 generic-y += mutex.h
 generic-y += percpu.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sections.h
@@ -31,5 +33,3 @@ generic-y += trace_clock.h
 generic-y += types.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/m68k/include/asm/barrier.h b/arch/m68k/include/asm/barrier.h
deleted file mode 100644 (file)
index 15c5f77..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _M68K_BARRIER_H
-#define _M68K_BARRIER_H
-
-#define nop()          do { asm volatile ("nop"); barrier(); } while (0)
-
-#include <asm-generic/barrier.h>
-
-#endif /* _M68K_BARRIER_H */
index 014f288fc81354e0eb088e500184e7e032ea6ba3..9d38b73989eb597d677acd95ea53cf0ddb99b624 100644 (file)
@@ -4,7 +4,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls            349
+#define NR_syscalls            351
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
index 625f321001dc077fe13da02eb0844a50099653dc..b932dd470041c2c5130dfcc44448c80033525259 100644 (file)
 #define __NR_process_vm_writev 346
 #define __NR_kcmp              347
 #define __NR_finit_module      348
+#define __NR_sched_setattr     349
+#define __NR_sched_getattr     350
 
 #endif /* _UAPI_ASM_M68K_UNISTD_H_ */
index 3f04ea0ab802750866835fcd9c3aa75ac7b28282..b6223dc41d82870953be64b35fc409c4b5634070 100644 (file)
@@ -369,4 +369,6 @@ ENTRY(sys_call_table)
        .long sys_process_vm_writev
        .long sys_kcmp
        .long sys_finit_module
+       .long sys_sched_setattr
+       .long sys_sched_getattr         /* 350 */
 
index 84fdf6857c31d1ccf878911b416f32e104eba8fb..a613d2c82fd9e7cbb024a28f493c0be54748d7e0 100644 (file)
@@ -200,10 +200,11 @@ static inline void __user *arch_compat_alloc_user_space(long len)
 
        /*
         * We can't access below the stack pointer in the 32bit ABI and
-        * can access 288 bytes in the 64bit ABI
+        * can access 288 bytes in the 64bit big-endian ABI,
+        * or 512 bytes with the new ELFv2 little-endian ABI.
         */
        if (!is_32bit_task())
-               usp -= 288;
+               usp -= USER_REDZONE_SIZE;
 
        return (void __user *) (usp - len);
 }
index 40157e2ca6914467cddae0225070d8582ad0861c..ed82142a325111ca18ecbc5ad05ec5760cb03a87 100644 (file)
@@ -816,8 +816,8 @@ int64_t opal_pci_next_error(uint64_t phb_id, uint64_t *first_frozen_pe,
 int64_t opal_pci_poll(uint64_t phb_id);
 int64_t opal_return_cpu(void);
 
-int64_t opal_xscom_read(uint32_t gcid, uint32_t pcb_addr, __be64 *val);
-int64_t opal_xscom_write(uint32_t gcid, uint32_t pcb_addr, uint64_t val);
+int64_t opal_xscom_read(uint32_t gcid, uint64_t pcb_addr, __be64 *val);
+int64_t opal_xscom_write(uint32_t gcid, uint64_t pcb_addr, uint64_t val);
 
 int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
                       uint32_t addr, uint32_t data, uint32_t sz);
index becc08e6a65c585e0b6bc995f7699d74e2c36338..279b80f3bb293d0bceceecb9eb38ff344e26b8fb 100644 (file)
 
 #ifdef __powerpc64__
 
+/*
+ * Size of redzone that userspace is allowed to use below the stack
+ * pointer.  This is 288 in the 64-bit big-endian ELF ABI, and 512 in
+ * the new ELFv2 little-endian ABI, so we allow the larger amount.
+ *
+ * For kernel code we allow a 288-byte redzone, in order to conserve
+ * kernel stack space; gcc currently only uses 288 bytes, and will
+ * hopefully allow explicit control of the redzone size in future.
+ */
+#define USER_REDZONE_SIZE      512
+#define KERNEL_REDZONE_SIZE    288
+
 #define STACK_FRAME_OVERHEAD   112     /* size of minimum stack frame */
 #define STACK_FRAME_LR_SAVE    2       /* Location of LR in stack frame */
 #define STACK_FRAME_REGS_MARKER        ASM_CONST(0x7265677368657265)
 #define STACK_INT_FRAME_SIZE   (sizeof(struct pt_regs) + \
-                                       STACK_FRAME_OVERHEAD + 288)
+                                STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE)
 #define STACK_FRAME_MARKER     12
 
 /* Size of dummy stack frame allocated when calling signal handler. */
@@ -41,6 +53,8 @@
 
 #else /* __powerpc64__ */
 
+#define USER_REDZONE_SIZE      0
+#define KERNEL_REDZONE_SIZE    0
 #define STACK_FRAME_OVERHEAD   16      /* size of minimum stack frame */
 #define STACK_FRAME_LR_SAVE    1       /* Location of LR in stack frame */
 #define STACK_FRAME_REGS_MARKER        ASM_CONST(0x72656773)
index 11c1d069d920a1fc97ec601ab0542c41708d7cc1..7a13f378ca2c7b1c715b9719e01329f99bf2ef2e 100644 (file)
@@ -98,17 +98,19 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
                        size_t csize, unsigned long offset, int userbuf)
 {
        void  *vaddr;
+       phys_addr_t paddr;
 
        if (!csize)
                return 0;
 
        csize = min_t(size_t, csize, PAGE_SIZE);
+       paddr = pfn << PAGE_SHIFT;
 
-       if ((min_low_pfn < pfn) && (pfn < max_pfn)) {
-               vaddr = __va(pfn << PAGE_SHIFT);
+       if (memblock_is_region_memory(paddr, csize)) {
+               vaddr = __va(paddr);
                csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
        } else {
-               vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0);
+               vaddr = __ioremap(paddr, PAGE_SIZE, 0);
                csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
                iounmap(vaddr);
        }
index 9b27b293a9226903c81529a4f01aee64a7f07d23..b0ded97ee4e11148cd436809aaab2c36c106893a 100644 (file)
@@ -74,6 +74,7 @@ ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
  */
 static int test_24bit_addr(unsigned long ip, unsigned long addr)
 {
+       addr = ppc_function_entry((void *)addr);
 
        /* use the create_branch to verify that this offset can be branched */
        return create_branch((unsigned int *)ip, addr, 0);
index 8d4c247f17389f283d02bc48dba044ff077e3ffe..af064d28b36524c5ce9c8fc982a58eec65ebbfc7 100644 (file)
@@ -1048,6 +1048,15 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
        flush_altivec_to_thread(src);
        flush_vsx_to_thread(src);
        flush_spe_to_thread(src);
+       /*
+        * Flush TM state out so we can copy it.  __switch_to_tm() does this
+        * flush but it removes the checkpointed state from the current CPU and
+        * transitions the CPU out of TM mode.  Hence we need to call
+        * tm_recheckpoint_new_task() (on the same task) to restore the
+        * checkpointed state back and the TM mode.
+        */
+       __switch_to_tm(src);
+       tm_recheckpoint_new_task(src);
 
        *dst = *src;
 
index 1482327cfeba9c1a846be00ae54e2606a1ac07b9..d88736fbece67c6627e6f33a9c4fd3e31ee2b533 100644 (file)
@@ -81,6 +81,7 @@ _GLOBAL(relocate)
 
 6:     blr
 
+.balign 8
 p_dyn: .llong  __dynamic_start - 0b
 p_rela:        .llong  __rela_dyn_start - 0b
 p_st:  .llong  _stext - 0b
index e35bf773df7a8d972990374cbb1507db261ccea2..8d253c29649b514e6f12694a5794329e008f1ea2 100644 (file)
@@ -65,8 +65,8 @@ struct rt_sigframe {
        struct siginfo __user *pinfo;
        void __user *puc;
        struct siginfo info;
-       /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
-       char abigap[288];
+       /* New 64 bit little-endian ABI allows redzone of 512 bytes below sp */
+       char abigap[USER_REDZONE_SIZE];
 } __attribute__ ((aligned (16)));
 
 static const char fmt32[] = KERN_INFO \
index 5ec1e47a0d771eba56e8b8c42111a19aed7df25a..e865d748179b2ac1b0b7550c1d3bebbcae71e049 100644 (file)
@@ -123,7 +123,8 @@ static int __init cbe_ptcal_enable_on_node(int nid, int order)
 
        area->nid = nid;
        area->order = order;
-       area->pages = alloc_pages_exact_node(area->nid, GFP_KERNEL|GFP_THISNODE,
+       area->pages = alloc_pages_exact_node(area->nid,
+                                               GFP_KERNEL|__GFP_THISNODE,
                                                area->order);
 
        if (!area->pages) {
index f5147433646025199c0524f2a7234cd653b432a7..253fefe3d1a0e76fd4ed3996711b6f1784725d6c 100644 (file)
@@ -114,6 +114,7 @@ DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbB_dbgfs_ops, ioda_eeh_inbB_dbgfs_get,
                        ioda_eeh_inbB_dbgfs_set, "0x%llx\n");
 #endif /* CONFIG_DEBUG_FS */
 
+
 /**
  * ioda_eeh_post_init - Chip dependent post initialization
  * @hose: PCI controller
@@ -221,6 +222,22 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
        return ret;
 }
 
+static void ioda_eeh_phb_diag(struct pci_controller *hose)
+{
+       struct pnv_phb *phb = hose->private_data;
+       long rc;
+
+       rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
+                                        PNV_PCI_DIAG_BUF_SIZE);
+       if (rc != OPAL_SUCCESS) {
+               pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
+                           __func__, hose->global_number, rc);
+               return;
+       }
+
+       pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
+}
+
 /**
  * ioda_eeh_get_state - Retrieve the state of PE
  * @pe: EEH PE
@@ -272,6 +289,9 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
                        result |= EEH_STATE_DMA_ACTIVE;
                        result |= EEH_STATE_MMIO_ENABLED;
                        result |= EEH_STATE_DMA_ENABLED;
+               } else if (!(pe->state & EEH_PE_ISOLATED)) {
+                       eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+                       ioda_eeh_phb_diag(hose);
                }
 
                return result;
@@ -315,6 +335,15 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
                           __func__, fstate, hose->global_number, pe_no);
        }
 
+       /* Dump PHB diag-data for frozen PE */
+       if (result != EEH_STATE_NOT_SUPPORT &&
+           (result & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) !=
+           (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE) &&
+           !(pe->state & EEH_PE_ISOLATED)) {
+               eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+               ioda_eeh_phb_diag(hose);
+       }
+
        return result;
 }
 
@@ -529,42 +558,6 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
        return ret;
 }
 
-/**
- * ioda_eeh_get_log - Retrieve error log
- * @pe: EEH PE
- * @severity: Severity level of the log
- * @drv_log: buffer to store the log
- * @len: space of the log buffer
- *
- * The function is used to retrieve error log from P7IOC.
- */
-static int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
-                           char *drv_log, unsigned long len)
-{
-       s64 ret;
-       unsigned long flags;
-       struct pci_controller *hose = pe->phb;
-       struct pnv_phb *phb = hose->private_data;
-
-       spin_lock_irqsave(&phb->lock, flags);
-
-       ret = opal_pci_get_phb_diag_data2(phb->opal_id,
-                       phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE);
-       if (ret) {
-               spin_unlock_irqrestore(&phb->lock, flags);
-               pr_warning("%s: Can't get log for PHB#%x-PE#%x (%lld)\n",
-                          __func__, hose->global_number, pe->addr, ret);
-               return -EIO;
-       }
-
-       /* The PHB diag-data is always indicative */
-       pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
-
-       spin_unlock_irqrestore(&phb->lock, flags);
-
-       return 0;
-}
-
 /**
  * ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE
  * @pe: EEH PE
@@ -646,22 +639,6 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
        }
 }
 
-static void ioda_eeh_phb_diag(struct pci_controller *hose)
-{
-       struct pnv_phb *phb = hose->private_data;
-       long rc;
-
-       rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
-                                        PNV_PCI_DIAG_BUF_SIZE);
-       if (rc != OPAL_SUCCESS) {
-               pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
-                           __func__, hose->global_number, rc);
-               return;
-       }
-
-       pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
-}
-
 static int ioda_eeh_get_phb_pe(struct pci_controller *hose,
                               struct eeh_pe **pe)
 {
@@ -834,6 +811,20 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
                                __func__, err_type);
                }
 
+               /*
+                * EEH core will try recover from fenced PHB or
+                * frozen PE. In the time for frozen PE, EEH core
+                * enable IO path for that before collecting logs,
+                * but it ruins the site. So we have to dump the
+                * log in advance here.
+                */
+               if ((ret == EEH_NEXT_ERR_FROZEN_PE  ||
+                   ret == EEH_NEXT_ERR_FENCED_PHB) &&
+                   !((*pe)->state & EEH_PE_ISOLATED)) {
+                       eeh_pe_state_mark(*pe, EEH_PE_ISOLATED);
+                       ioda_eeh_phb_diag(hose);
+               }
+
                /*
                 * If we have no errors on the specific PHB or only
                 * informative error there, we continue poking it.
@@ -852,7 +843,6 @@ struct pnv_eeh_ops ioda_eeh_ops = {
        .set_option             = ioda_eeh_set_option,
        .get_state              = ioda_eeh_get_state,
        .reset                  = ioda_eeh_reset,
-       .get_log                = ioda_eeh_get_log,
        .configure_bridge       = ioda_eeh_configure_bridge,
        .next_error             = ioda_eeh_next_error
 };
index 4fbf276ac99eeb4e2900196e3905a3343bedc988..4cd2ea6c0dbe13ecf2fb7926838cfeac9277730c 100644 (file)
@@ -71,11 +71,11 @@ static int opal_xscom_err_xlate(int64_t rc)
        }
 }
 
-static u64 opal_scom_unmangle(u64 reg)
+static u64 opal_scom_unmangle(u64 addr)
 {
        /*
         * XSCOM indirect addresses have the top bit set. Additionally
-        * the reset of the top 3 nibbles is always 0.
+        * the rest of the top 3 nibbles is always 0.
         *
         * Because the debugfs interface uses signed offsets and shifts
         * the address left by 3, we basically cannot use the top 4 bits
@@ -86,10 +86,13 @@ static u64 opal_scom_unmangle(u64 reg)
         * conversion here. To leave room for further xscom address
         * expansion, we only clear out the top byte
         *
+        * For in-kernel use, we also support the real indirect bit, so
+        * we test for any of the top 5 bits
+        *
         */
-       if (reg & (1ull << 59))
-               reg = (reg & ~(0xffull << 56)) | (1ull << 63);
-       return reg;
+       if (addr & (0x1full << 59))
+               addr = (addr & ~(0xffull << 56)) | (1ull << 63);
+       return addr;
 }
 
 static int opal_scom_read(scom_map_t map, u64 reg, u64 *value)
@@ -98,8 +101,8 @@ static int opal_scom_read(scom_map_t map, u64 reg, u64 *value)
        int64_t rc;
        __be64 v;
 
-       reg = opal_scom_unmangle(reg);
-       rc = opal_xscom_read(m->chip, m->addr + reg, (__be64 *)__pa(&v));
+       reg = opal_scom_unmangle(m->addr + reg);
+       rc = opal_xscom_read(m->chip, reg, (__be64 *)__pa(&v));
        *value = be64_to_cpu(v);
        return opal_xscom_err_xlate(rc);
 }
@@ -109,8 +112,8 @@ static int opal_scom_write(scom_map_t map, u64 reg, u64 value)
        struct opal_scom_map *m = map;
        int64_t rc;
 
-       reg = opal_scom_unmangle(reg);
-       rc = opal_xscom_write(m->chip, m->addr + reg, value);
+       reg = opal_scom_unmangle(m->addr + reg);
+       rc = opal_xscom_write(m->chip, reg, value);
        return opal_xscom_err_xlate(rc);
 }
 
index 95633d79ef5d6d3dd373ceed1552b05c8eed0a5c..8518817dcdfdc95d04e3b1fc10bfe54432330079 100644 (file)
@@ -134,57 +134,72 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
        pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n",
                hose->global_number, common->version);
 
-       pr_info("  brdgCtl:              %08x\n", data->brdgCtl);
-
-       pr_info("  portStatusReg:        %08x\n", data->portStatusReg);
-       pr_info("  rootCmplxStatus:      %08x\n", data->rootCmplxStatus);
-       pr_info("  busAgentStatus:       %08x\n", data->busAgentStatus);
-
-       pr_info("  deviceStatus:         %08x\n", data->deviceStatus);
-       pr_info("  slotStatus:           %08x\n", data->slotStatus);
-       pr_info("  linkStatus:           %08x\n", data->linkStatus);
-       pr_info("  devCmdStatus:         %08x\n", data->devCmdStatus);
-       pr_info("  devSecStatus:         %08x\n", data->devSecStatus);
-
-       pr_info("  rootErrorStatus:      %08x\n", data->rootErrorStatus);
-       pr_info("  uncorrErrorStatus:    %08x\n", data->uncorrErrorStatus);
-       pr_info("  corrErrorStatus:      %08x\n", data->corrErrorStatus);
-       pr_info("  tlpHdr1:              %08x\n", data->tlpHdr1);
-       pr_info("  tlpHdr2:              %08x\n", data->tlpHdr2);
-       pr_info("  tlpHdr3:              %08x\n", data->tlpHdr3);
-       pr_info("  tlpHdr4:              %08x\n", data->tlpHdr4);
-       pr_info("  sourceId:             %08x\n", data->sourceId);
-       pr_info("  errorClass:           %016llx\n", data->errorClass);
-       pr_info("  correlator:           %016llx\n", data->correlator);
-       pr_info("  p7iocPlssr:           %016llx\n", data->p7iocPlssr);
-       pr_info("  p7iocCsr:             %016llx\n", data->p7iocCsr);
-       pr_info("  lemFir:               %016llx\n", data->lemFir);
-       pr_info("  lemErrorMask:         %016llx\n", data->lemErrorMask);
-       pr_info("  lemWOF:               %016llx\n", data->lemWOF);
-       pr_info("  phbErrorStatus:       %016llx\n", data->phbErrorStatus);
-       pr_info("  phbFirstErrorStatus:  %016llx\n", data->phbFirstErrorStatus);
-       pr_info("  phbErrorLog0:         %016llx\n", data->phbErrorLog0);
-       pr_info("  phbErrorLog1:         %016llx\n", data->phbErrorLog1);
-       pr_info("  mmioErrorStatus:      %016llx\n", data->mmioErrorStatus);
-       pr_info("  mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
-       pr_info("  mmioErrorLog0:        %016llx\n", data->mmioErrorLog0);
-       pr_info("  mmioErrorLog1:        %016llx\n", data->mmioErrorLog1);
-       pr_info("  dma0ErrorStatus:      %016llx\n", data->dma0ErrorStatus);
-       pr_info("  dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
-       pr_info("  dma0ErrorLog0:        %016llx\n", data->dma0ErrorLog0);
-       pr_info("  dma0ErrorLog1:        %016llx\n", data->dma0ErrorLog1);
-       pr_info("  dma1ErrorStatus:      %016llx\n", data->dma1ErrorStatus);
-       pr_info("  dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
-       pr_info("  dma1ErrorLog0:        %016llx\n", data->dma1ErrorLog0);
-       pr_info("  dma1ErrorLog1:        %016llx\n", data->dma1ErrorLog1);
+       if (data->brdgCtl)
+               pr_info("  brdgCtl:     %08x\n",
+                       data->brdgCtl);
+       if (data->portStatusReg || data->rootCmplxStatus ||
+           data->busAgentStatus)
+               pr_info("  UtlSts:      %08x %08x %08x\n",
+                       data->portStatusReg, data->rootCmplxStatus,
+                       data->busAgentStatus);
+       if (data->deviceStatus || data->slotStatus   ||
+           data->linkStatus   || data->devCmdStatus ||
+           data->devSecStatus)
+               pr_info("  RootSts:     %08x %08x %08x %08x %08x\n",
+                       data->deviceStatus, data->slotStatus,
+                       data->linkStatus, data->devCmdStatus,
+                       data->devSecStatus);
+       if (data->rootErrorStatus   || data->uncorrErrorStatus ||
+           data->corrErrorStatus)
+               pr_info("  RootErrSts:  %08x %08x %08x\n",
+                       data->rootErrorStatus, data->uncorrErrorStatus,
+                       data->corrErrorStatus);
+       if (data->tlpHdr1 || data->tlpHdr2 ||
+           data->tlpHdr3 || data->tlpHdr4)
+               pr_info("  RootErrLog:  %08x %08x %08x %08x\n",
+                       data->tlpHdr1, data->tlpHdr2,
+                       data->tlpHdr3, data->tlpHdr4);
+       if (data->sourceId || data->errorClass ||
+           data->correlator)
+               pr_info("  RootErrLog1: %08x %016llx %016llx\n",
+                       data->sourceId, data->errorClass,
+                       data->correlator);
+       if (data->p7iocPlssr || data->p7iocCsr)
+               pr_info("  PhbSts:      %016llx %016llx\n",
+                       data->p7iocPlssr, data->p7iocCsr);
+       if (data->lemFir || data->lemErrorMask ||
+           data->lemWOF)
+               pr_info("  Lem:         %016llx %016llx %016llx\n",
+                       data->lemFir, data->lemErrorMask,
+                       data->lemWOF);
+       if (data->phbErrorStatus || data->phbFirstErrorStatus ||
+           data->phbErrorLog0   || data->phbErrorLog1)
+               pr_info("  PhbErr:      %016llx %016llx %016llx %016llx\n",
+                       data->phbErrorStatus, data->phbFirstErrorStatus,
+                       data->phbErrorLog0, data->phbErrorLog1);
+       if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
+           data->mmioErrorLog0   || data->mmioErrorLog1)
+               pr_info("  OutErr:      %016llx %016llx %016llx %016llx\n",
+                       data->mmioErrorStatus, data->mmioFirstErrorStatus,
+                       data->mmioErrorLog0, data->mmioErrorLog1);
+       if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
+           data->dma0ErrorLog0   || data->dma0ErrorLog1)
+               pr_info("  InAErr:      %016llx %016llx %016llx %016llx\n",
+                       data->dma0ErrorStatus, data->dma0FirstErrorStatus,
+                       data->dma0ErrorLog0, data->dma0ErrorLog1);
+       if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
+           data->dma1ErrorLog0   || data->dma1ErrorLog1)
+               pr_info("  InBErr:      %016llx %016llx %016llx %016llx\n",
+                       data->dma1ErrorStatus, data->dma1FirstErrorStatus,
+                       data->dma1ErrorLog0, data->dma1ErrorLog1);
 
        for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
                if ((data->pestA[i] >> 63) == 0 &&
                    (data->pestB[i] >> 63) == 0)
                        continue;
 
-               pr_info("  PE[%3d] PESTA:        %016llx\n", i, data->pestA[i]);
-               pr_info("          PESTB:        %016llx\n", data->pestB[i]);
+               pr_info("  PE[%3d] A/B: %016llx %016llx\n",
+                       i, data->pestA[i], data->pestB[i]);
        }
 }
 
@@ -197,62 +212,77 @@ static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose,
        data = (struct OpalIoPhb3ErrorData*)common;
        pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n",
                hose->global_number, common->version);
-
-       pr_info("  brdgCtl:              %08x\n", data->brdgCtl);
-
-       pr_info("  portStatusReg:        %08x\n", data->portStatusReg);
-       pr_info("  rootCmplxStatus:      %08x\n", data->rootCmplxStatus);
-       pr_info("  busAgentStatus:       %08x\n", data->busAgentStatus);
-
-       pr_info("  deviceStatus:         %08x\n", data->deviceStatus);
-       pr_info("  slotStatus:           %08x\n", data->slotStatus);
-       pr_info("  linkStatus:           %08x\n", data->linkStatus);
-       pr_info("  devCmdStatus:         %08x\n", data->devCmdStatus);
-       pr_info("  devSecStatus:         %08x\n", data->devSecStatus);
-
-       pr_info("  rootErrorStatus:      %08x\n", data->rootErrorStatus);
-       pr_info("  uncorrErrorStatus:    %08x\n", data->uncorrErrorStatus);
-       pr_info("  corrErrorStatus:      %08x\n", data->corrErrorStatus);
-       pr_info("  tlpHdr1:              %08x\n", data->tlpHdr1);
-       pr_info("  tlpHdr2:              %08x\n", data->tlpHdr2);
-       pr_info("  tlpHdr3:              %08x\n", data->tlpHdr3);
-       pr_info("  tlpHdr4:              %08x\n", data->tlpHdr4);
-       pr_info("  sourceId:             %08x\n", data->sourceId);
-       pr_info("  errorClass:           %016llx\n", data->errorClass);
-       pr_info("  correlator:           %016llx\n", data->correlator);
-
-       pr_info("  nFir:                 %016llx\n", data->nFir);
-       pr_info("  nFirMask:             %016llx\n", data->nFirMask);
-       pr_info("  nFirWOF:              %016llx\n", data->nFirWOF);
-       pr_info("  PhbPlssr:             %016llx\n", data->phbPlssr);
-       pr_info("  PhbCsr:               %016llx\n", data->phbCsr);
-       pr_info("  lemFir:               %016llx\n", data->lemFir);
-       pr_info("  lemErrorMask:         %016llx\n", data->lemErrorMask);
-       pr_info("  lemWOF:               %016llx\n", data->lemWOF);
-       pr_info("  phbErrorStatus:       %016llx\n", data->phbErrorStatus);
-       pr_info("  phbFirstErrorStatus:  %016llx\n", data->phbFirstErrorStatus);
-       pr_info("  phbErrorLog0:         %016llx\n", data->phbErrorLog0);
-       pr_info("  phbErrorLog1:         %016llx\n", data->phbErrorLog1);
-       pr_info("  mmioErrorStatus:      %016llx\n", data->mmioErrorStatus);
-       pr_info("  mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
-       pr_info("  mmioErrorLog0:        %016llx\n", data->mmioErrorLog0);
-       pr_info("  mmioErrorLog1:        %016llx\n", data->mmioErrorLog1);
-       pr_info("  dma0ErrorStatus:      %016llx\n", data->dma0ErrorStatus);
-       pr_info("  dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
-       pr_info("  dma0ErrorLog0:        %016llx\n", data->dma0ErrorLog0);
-       pr_info("  dma0ErrorLog1:        %016llx\n", data->dma0ErrorLog1);
-       pr_info("  dma1ErrorStatus:      %016llx\n", data->dma1ErrorStatus);
-       pr_info("  dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
-       pr_info("  dma1ErrorLog0:        %016llx\n", data->dma1ErrorLog0);
-       pr_info("  dma1ErrorLog1:        %016llx\n", data->dma1ErrorLog1);
+       if (data->brdgCtl)
+               pr_info("  brdgCtl:     %08x\n",
+                       data->brdgCtl);
+       if (data->portStatusReg || data->rootCmplxStatus ||
+           data->busAgentStatus)
+               pr_info("  UtlSts:      %08x %08x %08x\n",
+                       data->portStatusReg, data->rootCmplxStatus,
+                       data->busAgentStatus);
+       if (data->deviceStatus || data->slotStatus   ||
+           data->linkStatus   || data->devCmdStatus ||
+           data->devSecStatus)
+               pr_info("  RootSts:     %08x %08x %08x %08x %08x\n",
+                       data->deviceStatus, data->slotStatus,
+                       data->linkStatus, data->devCmdStatus,
+                       data->devSecStatus);
+       if (data->rootErrorStatus || data->uncorrErrorStatus ||
+           data->corrErrorStatus)
+               pr_info("  RootErrSts:  %08x %08x %08x\n",
+                       data->rootErrorStatus, data->uncorrErrorStatus,
+                       data->corrErrorStatus);
+       if (data->tlpHdr1 || data->tlpHdr2 ||
+           data->tlpHdr3 || data->tlpHdr4)
+               pr_info("  RootErrLog:  %08x %08x %08x %08x\n",
+                       data->tlpHdr1, data->tlpHdr2,
+                       data->tlpHdr3, data->tlpHdr4);
+       if (data->sourceId || data->errorClass ||
+           data->correlator)
+               pr_info("  RootErrLog1: %08x %016llx %016llx\n",
+                       data->sourceId, data->errorClass,
+                       data->correlator);
+       if (data->nFir || data->nFirMask ||
+           data->nFirWOF)
+               pr_info("  nFir:        %016llx %016llx %016llx\n",
+                       data->nFir, data->nFirMask,
+                       data->nFirWOF);
+       if (data->phbPlssr || data->phbCsr)
+               pr_info("  PhbSts:      %016llx %016llx\n",
+                       data->phbPlssr, data->phbCsr);
+       if (data->lemFir || data->lemErrorMask ||
+           data->lemWOF)
+               pr_info("  Lem:         %016llx %016llx %016llx\n",
+                       data->lemFir, data->lemErrorMask,
+                       data->lemWOF);
+       if (data->phbErrorStatus || data->phbFirstErrorStatus ||
+           data->phbErrorLog0   || data->phbErrorLog1)
+               pr_info("  PhbErr:      %016llx %016llx %016llx %016llx\n",
+                       data->phbErrorStatus, data->phbFirstErrorStatus,
+                       data->phbErrorLog0, data->phbErrorLog1);
+       if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
+           data->mmioErrorLog0   || data->mmioErrorLog1)
+               pr_info("  OutErr:      %016llx %016llx %016llx %016llx\n",
+                       data->mmioErrorStatus, data->mmioFirstErrorStatus,
+                       data->mmioErrorLog0, data->mmioErrorLog1);
+       if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
+           data->dma0ErrorLog0   || data->dma0ErrorLog1)
+               pr_info("  InAErr:      %016llx %016llx %016llx %016llx\n",
+                       data->dma0ErrorStatus, data->dma0FirstErrorStatus,
+                       data->dma0ErrorLog0, data->dma0ErrorLog1);
+       if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
+           data->dma1ErrorLog0   || data->dma1ErrorLog1)
+               pr_info("  InBErr:      %016llx %016llx %016llx %016llx\n",
+                       data->dma1ErrorStatus, data->dma1FirstErrorStatus,
+                       data->dma1ErrorLog0, data->dma1ErrorLog1);
 
        for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) {
                if ((data->pestA[i] >> 63) == 0 &&
                    (data->pestB[i] >> 63) == 0)
                        continue;
 
-               pr_info("  PE[%3d] PESTA:        %016llx\n", i, data->pestA[i]);
-               pr_info("          PESTB:        %016llx\n", data->pestB[i]);
+               pr_info("  PE[%3d] A/B: %016llx %016llx\n",
+                       i, data->pestA[i], data->pestB[i]);
        }
 }
 
index 82789e79e53985cf2b6c856f313628ff1eb0ca3e..0ea99e3d4815733a74b8098864f3594839ed97eb 100644 (file)
 #include "offline_states.h"
 
 /* This version can't take the spinlock, because it never returns */
-static struct rtas_args rtas_stop_self_args = {
-       .token = RTAS_UNKNOWN_SERVICE,
-       .nargs = 0,
-       .nret = 1,
-       .rets = &rtas_stop_self_args.args[0],
-};
+static int rtas_stop_self_token = RTAS_UNKNOWN_SERVICE;
 
 static DEFINE_PER_CPU(enum cpu_state_vals, preferred_offline_state) =
                                                        CPU_STATE_OFFLINE;
@@ -93,15 +88,20 @@ void set_default_offline_state(int cpu)
 
 static void rtas_stop_self(void)
 {
-       struct rtas_args *args = &rtas_stop_self_args;
+       struct rtas_args args = {
+               .token = cpu_to_be32(rtas_stop_self_token),
+               .nargs = 0,
+               .nret = 1,
+               .rets = &args.args[0],
+       };
 
        local_irq_disable();
 
-       BUG_ON(args->token == RTAS_UNKNOWN_SERVICE);
+       BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE);
 
        printk("cpu %u (hwid %u) Ready to die...\n",
               smp_processor_id(), hard_smp_processor_id());
-       enter_rtas(__pa(args));
+       enter_rtas(__pa(&args));
 
        panic("Alas, I survived.\n");
 }
@@ -392,10 +392,10 @@ static int __init pseries_cpu_hotplug_init(void)
                }
        }
 
-       rtas_stop_self_args.token = rtas_token("stop-self");
+       rtas_stop_self_token = rtas_token("stop-self");
        qcss_tok = rtas_token("query-cpu-stopped-state");
 
-       if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE ||
+       if (rtas_stop_self_token == RTAS_UNKNOWN_SERVICE ||
                        qcss_tok == RTAS_UNKNOWN_SERVICE) {
                printk(KERN_INFO "CPU Hotplug not supported by firmware "
                                "- disabling.\n");
index 59c8efce1b99b52964950f0933b4934a12b6a9db..0248949a756d7765d11a1d39f1568d37e3934406 100644 (file)
@@ -1421,5 +1421,5 @@ ENTRY(sys_sched_setattr_wrapper)
 ENTRY(sys_sched_getattr_wrapper)
        lgfr    %r2,%r2                 # pid_t
        llgtr   %r3,%r3                 # const char __user *
-       llgfr   %r3,%r3                 # unsigned int
+       llgfr   %r4,%r4                 # unsigned int
        jg      sys_sched_getattr
index 60c11a629d96d0220d6b01cf1e1425d41c0ffaab..f91c03119804751894c39433eb52da1844dbcf3b 100644 (file)
@@ -206,11 +206,13 @@ static void dma_cleanup_tables(struct zpci_dev *zdev)
        zdev->dma_table = NULL;
 }
 
-static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev, unsigned long start,
-                                  int size)
+static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev,
+                                      unsigned long start, int size)
 {
-       unsigned long boundary_size = 0x1000000;
+       unsigned long boundary_size;
 
+       boundary_size = ALIGN(dma_get_seg_boundary(&zdev->pdev->dev) + 1,
+                             PAGE_SIZE) >> PAGE_SHIFT;
        return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages,
                                start, size, 0, boundary_size, 0);
 }
index 673515bc413559a24600f988baeb91e8a6b9b1d4..aa1b2b9088a77b061758f48f4a434185e760d6ca 100644 (file)
@@ -18,7 +18,7 @@
 #define SH_CACHE_ASSOC         8
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7619)
-#define CCR            0xffffffec
+#define SH_CCR         0xffffffec
 
 #define CCR_CACHE_CE   0x01    /* Cache enable */
 #define CCR_CACHE_WT   0x02    /* CCR[bit1=1,bit2=1] */
index defb0baa5a0682b95222bccc60440ee760bd6680..b27ce92cb600bc17c47dacda12d0e3dc9f8d06a1 100644 (file)
@@ -17,8 +17,8 @@
 #define SH_CACHE_COMBINED      4
 #define SH_CACHE_ASSOC         8
 
-#define CCR            0xfffc1000 /* CCR1 */
-#define CCR2           0xfffc1004
+#define SH_CCR         0xfffc1000 /* CCR1 */
+#define SH_CCR2                0xfffc1004
 
 /*
  * Most of the SH-2A CCR1 definitions resemble the SH-4 ones. All others not
index bee2d81c56bfbde6392866f1d4bb05b58d1aa4b8..29700fd88c75d30be16340966c3013f1c880f076 100644 (file)
@@ -17,7 +17,7 @@
 #define SH_CACHE_COMBINED      4
 #define SH_CACHE_ASSOC         8
 
-#define CCR            0xffffffec      /* Address of Cache Control Register */
+#define SH_CCR         0xffffffec      /* Address of Cache Control Register */
 
 #define CCR_CACHE_CE   0x01    /* Cache Enable */
 #define CCR_CACHE_WT   0x02    /* Write-Through (for P0,U0,P3) (else writeback) */
index 7bfb9e8b069c22d789318085e866440502f0c755..92c4cd119b662f99dc4ed9d0f5d1b54dea3001a9 100644 (file)
@@ -17,7 +17,7 @@
 #define SH_CACHE_COMBINED      4
 #define SH_CACHE_ASSOC         8
 
-#define CCR            0xff00001c      /* Address of Cache Control Register */
+#define SH_CCR         0xff00001c      /* Address of Cache Control Register */
 #define CCR_CACHE_OCE  0x0001  /* Operand Cache Enable */
 #define CCR_CACHE_WT   0x0002  /* Write-Through (for P0,U0,P3) (else writeback)*/
 #define CCR_CACHE_CB   0x0004  /* Copy-Back (for P1) (else writethrough) */
index ecf83cd158dc38fefb91f2fa83cdb452cfa5c6bf..0d7360d549c17858c59f93b6dc0d279f4222a640 100644 (file)
@@ -112,7 +112,7 @@ static void cache_init(void)
        unsigned long ccr, flags;
 
        jump_to_uncached();
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
 
        /*
         * At this point we don't know whether the cache is enabled or not - a
@@ -189,7 +189,7 @@ static void cache_init(void)
 
        l2_cache_init();
 
-       __raw_writel(flags, CCR);
+       __raw_writel(flags, SH_CCR);
        back_to_cached();
 }
 #else
index 115725198038da862a19ef634a0ec38adf23b76f..777e50f33c00f3f96fe4b34f7723132507b13935 100644 (file)
@@ -36,7 +36,7 @@ static int cache_seq_show(struct seq_file *file, void *iter)
         */
        jump_to_uncached();
 
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
        if ((ccr & CCR_CACHE_ENABLE) == 0) {
                back_to_cached();
 
index defcf719f2e84eb5cae2b6be57fed58227eeb6ec..a74259f2f9815e93d499634b67d9756472662e76 100644 (file)
@@ -63,9 +63,9 @@ static void sh2__flush_invalidate_region(void *start, int size)
        local_irq_save(flags);
        jump_to_uncached();
 
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
        ccr |= CCR_CACHE_INVALIDATE;
-       __raw_writel(ccr, CCR);
+       __raw_writel(ccr, SH_CCR);
 
        back_to_cached();
        local_irq_restore(flags);
index 949e2d3138a0ca24ffe07e6228a68eeeb72321e9..ee87d081259b86950d527151618a3e52814ade5a 100644 (file)
@@ -134,7 +134,8 @@ static void sh2a__flush_invalidate_region(void *start, int size)
 
        /* If there are too many pages then just blow the cache */
        if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) {
-               __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
+               __raw_writel(__raw_readl(SH_CCR) | CCR_OCACHE_INVALIDATE,
+                            SH_CCR);
        } else {
                for (v = begin; v < end; v += L1_CACHE_BYTES)
                        sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v);
@@ -167,7 +168,8 @@ static void sh2a_flush_icache_range(void *args)
        /* I-Cache invalidate */
        /* If there are too many pages then just blow the cache */
        if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) {
-               __raw_writel(__raw_readl(CCR) | CCR_ICACHE_INVALIDATE, CCR);
+               __raw_writel(__raw_readl(SH_CCR) | CCR_ICACHE_INVALIDATE,
+                            SH_CCR);
        } else {
                for (v = start; v < end; v += L1_CACHE_BYTES)
                        sh2a_invalidate_line(CACHE_IC_ADDRESS_ARRAY, v);
index 0e529285b28d42c688fb0901349ba70218385d51..51d8f7f31d1d797392ab2813f4fb3d4d33480598 100644 (file)
@@ -133,9 +133,9 @@ static void flush_icache_all(void)
        jump_to_uncached();
 
        /* Flush I-cache */
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
        ccr |= CCR_CACHE_ICI;
-       __raw_writel(ccr, CCR);
+       __raw_writel(ccr, SH_CCR);
 
        /*
         * back_to_cached() will take care of the barrier for us, don't add
index c0adbee97b5f29a2cdb33f6124c1d62ee821ebec..24c58b7dc02265c795000fa997ac96da59207175 100644 (file)
@@ -19,7 +19,7 @@ void __init shx3_cache_init(void)
 {
        unsigned int ccr;
 
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
 
        /*
         * If we've got cache aliases, resolve them in hardware.
@@ -40,5 +40,5 @@ void __init shx3_cache_init(void)
        ccr |= CCR_CACHE_IBE;
 #endif
 
-       writel_uncached(ccr, CCR);
+       writel_uncached(ccr, SH_CCR);
 }
index 616966a96cba61d6a680d4bc57cf71150a04fb3e..097c2cdd117f53c543fb919ba6740210b1471a4a 100644 (file)
@@ -285,8 +285,8 @@ void __init cpu_cache_init(void)
 {
        unsigned int cache_disabled = 0;
 
-#ifdef CCR
-       cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE);
+#ifdef SH_CCR
+       cache_disabled = !(__raw_readl(SH_CCR) & CCR_CACHE_ENABLE);
 #endif
 
        compute_alias(&boot_cpu_data.icache);
index c51efdcd07a2d09e76c06e31671efcd19a6db4ed..7d8b7e94b93b6fb8e9795f49368c056053597bec 100644 (file)
@@ -27,7 +27,7 @@ config SPARC
        select RTC_DRV_M48T59
        select HAVE_DMA_ATTRS
        select HAVE_DMA_API_DEBUG
-       select HAVE_ARCH_JUMP_LABEL
+       select HAVE_ARCH_JUMP_LABEL if SPARC64
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_IPC_PARSE_VERSION
        select GENERIC_PCI_IOMAP
index 869023abe5a4440c3ec08777e987c7abcc9777b8..cfbe53c17b0dbb61b25f8ae48c0f3017f307cc6f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
 #include <linux/kdebug.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/log2.h>
@@ -62,6 +63,7 @@ extern unsigned long last_valid_pfn;
 static pgd_t *srmmu_swapper_pg_dir;
 
 const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops;
+EXPORT_SYMBOL(sparc32_cachetlb_ops);
 
 #ifdef CONFIG_SMP
 const struct sparc32_cachetlb_ops *local_ops;
index c026cca5602c6fe5c84619f0b43b2fe7c3bb2382..f3aaf231b4e590fad07b58b51583eb6693a924cd 100644 (file)
@@ -341,10 +341,6 @@ config X86_USE_3DNOW
        def_bool y
        depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML
 
-config X86_OOSTORE
-       def_bool y
-       depends on (MWINCHIP3D || MWINCHIPC6) && MTRR
-
 #
 # P6_NOPs are a relatively minor optimization that require a family >=
 # 6 processor, except that it is broken on certain VIA chips.
index 90a21f430117d1690f847c8b198e80d6afb3c825..4dbf967da50daab8c7ed9f3952fa08b18b5b6271 100644 (file)
@@ -111,7 +111,7 @@ struct mem_vector {
 };
 
 #define MEM_AVOID_MAX 5
-struct mem_vector mem_avoid[MEM_AVOID_MAX];
+static struct mem_vector mem_avoid[MEM_AVOID_MAX];
 
 static bool mem_contains(struct mem_vector *region, struct mem_vector *item)
 {
@@ -180,7 +180,7 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
 }
 
 /* Does this memory vector overlap a known avoided area? */
-bool mem_avoid_overlap(struct mem_vector *img)
+static bool mem_avoid_overlap(struct mem_vector *img)
 {
        int i;
 
@@ -192,8 +192,9 @@ bool mem_avoid_overlap(struct mem_vector *img)
        return false;
 }
 
-unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET / CONFIG_PHYSICAL_ALIGN];
-unsigned long slot_max = 0;
+static unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET /
+                          CONFIG_PHYSICAL_ALIGN];
+static unsigned long slot_max;
 
 static void slots_append(unsigned long addr)
 {
index 04a48903b2eb31973080d60d36cfd93b3fc68a5f..69bbb484502089b6a01d93d58e4c16a3f90e14f9 100644 (file)
 #else
 # define smp_rmb()     barrier()
 #endif
-#ifdef CONFIG_X86_OOSTORE
-# define smp_wmb()     wmb()
-#else
-# define smp_wmb()     barrier()
-#endif
+#define smp_wmb()      barrier()
 #define smp_read_barrier_depends()     read_barrier_depends()
 #define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
 #else /* !SMP */
 #define set_mb(var, value) do { var = value; barrier(); } while (0)
 #endif /* SMP */
 
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
 
 /*
  * For either of these options x86 doesn't have a strong TSO memory
index 3d6b9f81cc683e63fbdac6c3243ab7069087e0cd..acd86c850414e7f3adfffe860ffd22bd17e0d459 100644 (file)
@@ -134,6 +134,7 @@ extern void efi_setup_page_tables(void);
 extern void __init old_map_region(efi_memory_desc_t *md);
 extern void __init runtime_code_page_mkexec(void);
 extern void __init efi_runtime_mkexec(void);
+extern void __init efi_apply_memmap_quirks(void);
 
 struct efi_setup_data {
        u64 fw_vendor;
index 34f69cb9350ae3ecf36e4b8cd8d410a6a7b67a0b..91d9c69a629e2731f25aa152de91dd17663ec619 100644 (file)
@@ -237,7 +237,7 @@ memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
 
 static inline void flush_write_buffers(void)
 {
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
        asm volatile("lock; addl $0,0(%%esp)": : :"memory");
 #endif
 }
index bf156ded74b56006a76cc02b8917984117af8afd..0f62f5482d91ec8fca86e884b6822fc467239dbc 100644 (file)
 # define LOCK_PTR_REG "D"
 #endif
 
-#if defined(CONFIG_X86_32) && \
-       (defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE))
+#if defined(CONFIG_X86_32) && (defined(CONFIG_X86_PPRO_FENCE))
 /*
- * On PPro SMP or if we are using OOSTORE, we use a locked operation to unlock
+ * On PPro SMP, we use a locked operation to unlock
  * (PPro errata 66, 92)
  */
 # define UNLOCK_LOCK_PREFIX LOCK_PREFIX
index 57ae63cd6ee2ec8aba5135a33e363267b65e4075..94605c0e9ceebc0058b18b995a5ac4f73a0d2aa6 100644 (file)
@@ -66,6 +66,6 @@ extern void tsc_save_sched_clock_state(void);
 extern void tsc_restore_sched_clock_state(void);
 
 /* MSR based TSC calibration for Intel Atom SoC platforms */
-int try_msr_calibrate_tsc(unsigned long *fast_calibrate);
+unsigned long try_msr_calibrate_tsc(void);
 
 #endif /* _ASM_X86_TSC_H */
index 8779edab684efdcd04fd93d22d79d4633c6fd4f9..d8fba5c15fbd8882f317daa2779c39ff4429b0d4 100644 (file)
@@ -8,236 +8,6 @@
 
 #include "cpu.h"
 
-#ifdef CONFIG_X86_OOSTORE
-
-static u32 power2(u32 x)
-{
-       u32 s = 1;
-
-       while (s <= x)
-               s <<= 1;
-
-       return s >>= 1;
-}
-
-
-/*
- * Set up an actual MCR
- */
-static void centaur_mcr_insert(int reg, u32 base, u32 size, int key)
-{
-       u32 lo, hi;
-
-       hi = base & ~0xFFF;
-       lo = ~(size-1);         /* Size is a power of 2 so this makes a mask */
-       lo &= ~0xFFF;           /* Remove the ctrl value bits */
-       lo |= key;              /* Attribute we wish to set */
-       wrmsr(reg+MSR_IDT_MCR0, lo, hi);
-       mtrr_centaur_report_mcr(reg, lo, hi);   /* Tell the mtrr driver */
-}
-
-/*
- * Figure what we can cover with MCR's
- *
- * Shortcut: We know you can't put 4Gig of RAM on a winchip
- */
-static u32 ramtop(void)
-{
-       u32 clip = 0xFFFFFFFFUL;
-       u32 top = 0;
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               unsigned long start, end;
-
-               if (e820.map[i].addr > 0xFFFFFFFFUL)
-                       continue;
-               /*
-                * Don't MCR over reserved space. Ignore the ISA hole
-                * we frob around that catastrophe already
-                */
-               if (e820.map[i].type == E820_RESERVED) {
-                       if (e820.map[i].addr >= 0x100000UL &&
-                           e820.map[i].addr < clip)
-                               clip = e820.map[i].addr;
-                       continue;
-               }
-               start = e820.map[i].addr;
-               end = e820.map[i].addr + e820.map[i].size;
-               if (start >= end)
-                       continue;
-               if (end > top)
-                       top = end;
-       }
-       /*
-        * Everything below 'top' should be RAM except for the ISA hole.
-        * Because of the limited MCR's we want to map NV/ACPI into our
-        * MCR range for gunk in RAM
-        *
-        * Clip might cause us to MCR insufficient RAM but that is an
-        * acceptable failure mode and should only bite obscure boxes with
-        * a VESA hole at 15Mb
-        *
-        * The second case Clip sometimes kicks in is when the EBDA is marked
-        * as reserved. Again we fail safe with reasonable results
-        */
-       if (top > clip)
-               top = clip;
-
-       return top;
-}
-
-/*
- * Compute a set of MCR's to give maximum coverage
- */
-static int centaur_mcr_compute(int nr, int key)
-{
-       u32 mem = ramtop();
-       u32 root = power2(mem);
-       u32 base = root;
-       u32 top = root;
-       u32 floor = 0;
-       int ct = 0;
-
-       while (ct < nr) {
-               u32 fspace = 0;
-               u32 high;
-               u32 low;
-
-               /*
-                * Find the largest block we will fill going upwards
-                */
-               high = power2(mem-top);
-
-               /*
-                * Find the largest block we will fill going downwards
-                */
-               low = base/2;
-
-               /*
-                * Don't fill below 1Mb going downwards as there
-                * is an ISA hole in the way.
-                */
-               if (base <= 1024*1024)
-                       low = 0;
-
-               /*
-                * See how much space we could cover by filling below
-                * the ISA hole
-                */
-
-               if (floor == 0)
-                       fspace = 512*1024;
-               else if (floor == 512*1024)
-                       fspace = 128*1024;
-
-               /* And forget ROM space */
-
-               /*
-                * Now install the largest coverage we get
-                */
-               if (fspace > high && fspace > low) {
-                       centaur_mcr_insert(ct, floor, fspace, key);
-                       floor += fspace;
-               } else if (high > low) {
-                       centaur_mcr_insert(ct, top, high, key);
-                       top += high;
-               } else if (low > 0) {
-                       base -= low;
-                       centaur_mcr_insert(ct, base, low, key);
-               } else
-                       break;
-               ct++;
-       }
-       /*
-        * We loaded ct values. We now need to set the mask. The caller
-        * must do this bit.
-        */
-       return ct;
-}
-
-static void centaur_create_optimal_mcr(void)
-{
-       int used;
-       int i;
-
-       /*
-        * Allocate up to 6 mcrs to mark as much of ram as possible
-        * as write combining and weak write ordered.
-        *
-        * To experiment with: Linux never uses stack operations for
-        * mmio spaces so we could globally enable stack operation wc
-        *
-        * Load the registers with type 31 - full write combining, all
-        * writes weakly ordered.
-        */
-       used = centaur_mcr_compute(6, 31);
-
-       /*
-        * Wipe unused MCRs
-        */
-       for (i = used; i < 8; i++)
-               wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-static void winchip2_create_optimal_mcr(void)
-{
-       u32 lo, hi;
-       int used;
-       int i;
-
-       /*
-        * Allocate up to 6 mcrs to mark as much of ram as possible
-        * as write combining, weak store ordered.
-        *
-        * Load the registers with type 25
-        *      8       -       weak write ordering
-        *      16      -       weak read ordering
-        *      1       -       write combining
-        */
-       used = centaur_mcr_compute(6, 25);
-
-       /*
-        * Mark the registers we are using.
-        */
-       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-       for (i = 0; i < used; i++)
-               lo |= 1<<(9+i);
-       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-
-       /*
-        * Wipe unused MCRs
-        */
-
-       for (i = used; i < 8; i++)
-               wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-/*
- * Handle the MCR key on the Winchip 2.
- */
-static void winchip2_unprotect_mcr(void)
-{
-       u32 lo, hi;
-       u32 key;
-
-       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-       lo &= ~0x1C0;   /* blank bits 8-6 */
-       key = (lo>>17) & 7;
-       lo |= key<<6;   /* replace with unlock key */
-       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-
-static void winchip2_protect_mcr(void)
-{
-       u32 lo, hi;
-
-       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-       lo &= ~0x1C0;   /* blank bits 8-6 */
-       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-#endif /* CONFIG_X86_OOSTORE */
-
 #define ACE_PRESENT    (1 << 6)
 #define ACE_ENABLED    (1 << 7)
 #define ACE_FCR                (1 << 28)       /* MSR_VIA_FCR */
@@ -362,20 +132,6 @@ static void init_centaur(struct cpuinfo_x86 *c)
                        fcr_clr = DPDC;
                        printk(KERN_NOTICE "Disabling bugged TSC.\n");
                        clear_cpu_cap(c, X86_FEATURE_TSC);
-#ifdef CONFIG_X86_OOSTORE
-                       centaur_create_optimal_mcr();
-                       /*
-                        * Enable:
-                        *      write combining on non-stack, non-string
-                        *      write combining on string, all types
-                        *      weak write ordering
-                        *
-                        * The C6 original lacks weak read order
-                        *
-                        * Note 0x120 is write only on Winchip 1
-                        */
-                       wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);
-#endif
                        break;
                case 8:
                        switch (c->x86_mask) {
@@ -392,40 +148,12 @@ static void init_centaur(struct cpuinfo_x86 *c)
                        fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
                                  E2MMX|EAMD3D;
                        fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
-                       winchip2_unprotect_mcr();
-                       winchip2_create_optimal_mcr();
-                       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       /*
-                        * Enable:
-                        *      write combining on non-stack, non-string
-                        *      write combining on string, all types
-                        *      weak write ordering
-                        */
-                       lo |= 31;
-                       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       winchip2_protect_mcr();
-#endif
                        break;
                case 9:
                        name = "3";
                        fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
                                  E2MMX|EAMD3D;
                        fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
-                       winchip2_unprotect_mcr();
-                       winchip2_create_optimal_mcr();
-                       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       /*
-                        * Enable:
-                        *      write combining on non-stack, non-string
-                        *      write combining on string, all types
-                        *      weak write ordering
-                        */
-                       lo |= 31;
-                       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       winchip2_protect_mcr();
-#endif
                        break;
                default:
                        name = "??";
index b88645191fe559b89b8d330c984865d07dbae21b..79f9f848bee4b1c021b80bed07e0dcbcec88a20b 100644 (file)
@@ -1192,6 +1192,9 @@ static void x86_pmu_del(struct perf_event *event, int flags)
        for (i = 0; i < cpuc->n_events; i++) {
                if (event == cpuc->event_list[i]) {
 
+                       if (i >= cpuc->n_events - cpuc->n_added)
+                               --cpuc->n_added;
+
                        if (x86_pmu.put_event_constraints)
                                x86_pmu.put_event_constraints(cpuc, event);
 
@@ -1521,6 +1524,8 @@ static int __init init_hw_perf_events(void)
 
        pr_cont("%s PMU driver.\n", x86_pmu.name);
 
+       x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
+
        for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next)
                quirk->func();
 
@@ -1534,7 +1539,6 @@ static int __init init_hw_perf_events(void)
                __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1,
                                   0, x86_pmu.num_counters, 0, 0);
 
-       x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
        x86_pmu_format_group.attrs = x86_pmu.format_attrs;
 
        if (x86_pmu.event_attrs)
@@ -1820,9 +1824,12 @@ static ssize_t set_attr_rdpmc(struct device *cdev,
        if (ret)
                return ret;
 
+       if (x86_pmu.attr_rdpmc_broken)
+               return -ENOTSUPP;
+
        if (!!val != !!x86_pmu.attr_rdpmc) {
                x86_pmu.attr_rdpmc = !!val;
-               smp_call_function(change_rdpmc, (void *)val, 1);
+               on_each_cpu(change_rdpmc, (void *)val, 1);
        }
 
        return count;
index c1a861829d817a2749372060df21c6d689294fff..4972c244d0bc2fbe445706943e0248073fd17a26 100644 (file)
@@ -409,6 +409,7 @@ struct x86_pmu {
        /*
         * sysfs attrs
         */
+       int             attr_rdpmc_broken;
        int             attr_rdpmc;
        struct attribute **format_attrs;
        struct attribute **event_attrs;
index 0fa4f242f0504ad53297360966e957b84a0edab8..aa333d9668866f808955209f8cd71737d447eafc 100644 (file)
@@ -1361,10 +1361,8 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
        intel_pmu_disable_all();
        handled = intel_pmu_drain_bts_buffer();
        status = intel_pmu_get_status();
-       if (!status) {
-               intel_pmu_enable_all(0);
-               return handled;
-       }
+       if (!status)
+               goto done;
 
        loops = 0;
 again:
@@ -2310,10 +2308,7 @@ __init int intel_pmu_init(void)
        if (version > 1)
                x86_pmu.num_counters_fixed = max((int)edx.split.num_counters_fixed, 3);
 
-       /*
-        * v2 and above have a perf capabilities MSR
-        */
-       if (version > 1) {
+       if (boot_cpu_has(X86_FEATURE_PDCM)) {
                u64 capabilities;
 
                rdmsrl(MSR_IA32_PERF_CAPABILITIES, capabilities);
index 29c248799cede4432ac2d57ca8689a215c35d0cc..c88f7f4b03ee063ba090ec1e53c864fa4279fdec 100644 (file)
@@ -501,8 +501,11 @@ static struct extra_reg snbep_uncore_cbox_extra_regs[] = {
        SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
                                  SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6),
        SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
@@ -1178,10 +1181,15 @@ static struct extra_reg ivt_uncore_cbox_extra_regs[] = {
        SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
                                  SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
        SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
        SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
index b1e2fe11532329bb9828ac4407f6b10093073187..7c1a0c07b607f1d882781978e1d08a8a94a546d2 100644 (file)
@@ -231,31 +231,49 @@ static __initconst const struct x86_pmu p6_pmu = {
 
 };
 
+static __init void p6_pmu_rdpmc_quirk(void)
+{
+       if (boot_cpu_data.x86_mask < 9) {
+               /*
+                * PPro erratum 26; fixed in stepping 9 and above.
+                */
+               pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n");
+               x86_pmu.attr_rdpmc_broken = 1;
+               x86_pmu.attr_rdpmc = 0;
+       }
+}
+
 __init int p6_pmu_init(void)
 {
+       x86_pmu = p6_pmu;
+
        switch (boot_cpu_data.x86_model) {
-       case 1:
-       case 3:  /* Pentium Pro */
-       case 5:
-       case 6:  /* Pentium II */
-       case 7:
-       case 8:
-       case 11: /* Pentium III */
-       case 9:
-       case 13:
-               /* Pentium M */
+       case  1: /* Pentium Pro */
+               x86_add_quirk(p6_pmu_rdpmc_quirk);
+               break;
+
+       case  3: /* Pentium II - Klamath */
+       case  5: /* Pentium II - Deschutes */
+       case  6: /* Pentium II - Mendocino */
                break;
+
+       case  7: /* Pentium III - Katmai */
+       case  8: /* Pentium III - Coppermine */
+       case 10: /* Pentium III Xeon */
+       case 11: /* Pentium III - Tualatin */
+               break;
+
+       case  9: /* Pentium M - Banias */
+       case 13: /* Pentium M - Dothan */
+               break;
+
        default:
-               pr_cont("unsupported p6 CPU model %d ",
-                       boot_cpu_data.x86_model);
+               pr_cont("unsupported p6 CPU model %d ", boot_cpu_data.x86_model);
                return -ENODEV;
        }
 
-       x86_pmu = p6_pmu;
-
        memcpy(hw_cache_event_ids, p6_hw_cache_event_ids,
                sizeof(hw_cache_event_ids));
 
-
        return 0;
 }
index 81ba27679f18ec6100bd167c3739608631a7c475..f36bd42d6f0c8b5fc5cd75dcf133b35a1f6bfe3b 100644 (file)
@@ -544,6 +544,10 @@ ENDPROC(early_idt_handlers)
        /* This is global to keep gas from relaxing the jumps */
 ENTRY(early_idt_handler)
        cld
+
+       cmpl $2,(%esp)          # X86_TRAP_NMI
+       je is_nmi               # Ignore NMI
+
        cmpl $2,%ss:early_recursion_flag
        je hlt_loop
        incl %ss:early_recursion_flag
@@ -594,8 +598,9 @@ ex_entry:
        pop %edx
        pop %ecx
        pop %eax
-       addl $8,%esp            /* drop vector number and error code */
        decl %ss:early_recursion_flag
+is_nmi:
+       addl $8,%esp            /* drop vector number and error code */
        iret
 ENDPROC(early_idt_handler)
 
index e1aabdb314c83740dd686eb4c70a6f40c312e258..a468c0a65c42e00df4e10afd9921d81a53dbba3d 100644 (file)
@@ -343,6 +343,9 @@ early_idt_handlers:
 ENTRY(early_idt_handler)
        cld
 
+       cmpl $2,(%rsp)          # X86_TRAP_NMI
+       je is_nmi               # Ignore NMI
+
        cmpl $2,early_recursion_flag(%rip)
        jz  1f
        incl early_recursion_flag(%rip)
@@ -405,8 +408,9 @@ ENTRY(early_idt_handler)
        popq %rdx
        popq %rcx
        popq %rax
-       addq $16,%rsp           # drop vector number and error code
        decl early_recursion_flag(%rip)
+is_nmi:
+       addq $16,%rsp           # drop vector number and error code
        INTERRUPT_RETURN
 ENDPROC(early_idt_handler)
 
index e8368c6dd2a2988c2d9d68cacc7030554424ad70..d5dd808144190ffd1d443229b4dbbd56740fface 100644 (file)
@@ -86,10 +86,19 @@ EXPORT_SYMBOL(__kernel_fpu_begin);
 
 void __kernel_fpu_end(void)
 {
-       if (use_eager_fpu())
-               math_state_restore();
-       else
+       if (use_eager_fpu()) {
+               /*
+                * For eager fpu, most the time, tsk_used_math() is true.
+                * Restore the user math as we are done with the kernel usage.
+                * At few instances during thread exit, signal handling etc,
+                * tsk_used_math() is false. Those few places will take proper
+                * actions, so we don't need to restore the math here.
+                */
+               if (likely(tsk_used_math(current)))
+                       math_state_restore();
+       } else {
                stts();
+       }
 }
 EXPORT_SYMBOL(__kernel_fpu_end);
 
index 4eabc160696f510ec5ffaddc7939dd71856463d5..679cef0791cd842448216f4a6158cd2ae24fe0e0 100644 (file)
@@ -279,5 +279,7 @@ void arch_crash_save_vmcoreinfo(void)
        VMCOREINFO_SYMBOL(node_data);
        VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
 #endif
+       vmcoreinfo_append_str("KERNELOFFSET=%lx\n",
+                             (unsigned long)&_text - __START_KERNEL);
 }
 
index 872079a67e4d262151dfdbe74f537033be5ebcc0..f7d0672481fd7c328682d601467313acb586280a 100644 (file)
@@ -100,8 +100,10 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
        flag |= __GFP_ZERO;
 again:
        page = NULL;
-       if (!(flag & GFP_ATOMIC))
+       /* CMA can be used only in the context which permits sleeping */
+       if (flag & __GFP_WAIT)
                page = dma_alloc_from_contiguous(dev, count, get_order(size));
+       /* fallback */
        if (!page)
                page = alloc_pages_node(dev_to_node(dev), flag, get_order(size));
        if (!page)
index 7c6acd4b8995e532f5422a03a7fb65c716cbf35d..ff898bbf579d7f34ce7b8c98a5482f72e4d338bf 100644 (file)
@@ -529,7 +529,7 @@ static void quirk_amd_nb_node(struct pci_dev *dev)
                return;
 
        pci_read_config_dword(nb_ht, 0x60, &val);
-       node = val & 7;
+       node = pcibus_to_node(dev->bus) | (val & 7);
        /*
         * Some hardware may return an invalid node ID,
         * so check it first:
index 06853e6703541f8349106e17330f86621fa984db..ce72964b2f469db1b3c626ecadc18c2998ef98a4 100644 (file)
@@ -1239,14 +1239,8 @@ void __init setup_arch(char **cmdline_p)
        register_refined_jiffies(CLOCK_TICK_RATE);
 
 #ifdef CONFIG_EFI
-       /* Once setup is done above, unmap the EFI memory map on
-        * mismatched firmware/kernel archtectures since there is no
-        * support for runtime services.
-        */
-       if (efi_enabled(EFI_BOOT) && !efi_is_native()) {
-               pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
-               efi_unmap_memmap();
-       }
+       if (efi_enabled(EFI_BOOT))
+               efi_apply_memmap_quirks();
 #endif
 }
 
index acb3b606613eb5b4937cdacab17adc74c4ec2c30..cfbe99f888300d819b53552a7668ab9bd12c3708 100644 (file)
@@ -653,13 +653,10 @@ unsigned long native_calibrate_tsc(void)
 
        /* Calibrate TSC using MSR for Intel Atom SoCs */
        local_irq_save(flags);
-       i = try_msr_calibrate_tsc(&fast_calibrate);
+       fast_calibrate = try_msr_calibrate_tsc();
        local_irq_restore(flags);
-       if (i >= 0) {
-               if (i == 0)
-                       pr_warn("Fast TSC calibration using MSR failed\n");
+       if (fast_calibrate)
                return fast_calibrate;
-       }
 
        local_irq_save(flags);
        fast_calibrate = quick_pit_calibrate();
index 8b5434f4389fc4afbbc7d297ab61ec403aedb9d8..92ae6acac8a7fbcb9b91cb386b3c23015c5377ea 100644 (file)
@@ -53,7 +53,7 @@ static struct freq_desc freq_desc_tables[] = {
        /* TNG */
        { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
        /* VLV2 */
-       { 6, 0x37, 1, { 0, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
+       { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
        /* ANN */
        { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } },
 };
@@ -77,21 +77,18 @@ static int match_cpu(u8 family, u8 model)
 
 /*
  * Do MSR calibration only for known/supported CPUs.
- * Return values:
- * -1: CPU is unknown/unsupported for MSR based calibration
- *  0: CPU is known/supported, but calibration failed
- *  1: CPU is known/supported, and calibration succeeded
+ *
+ * Returns the calibration value or 0 if MSR calibration failed.
  */
-int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
+unsigned long try_msr_calibrate_tsc(void)
 {
-       int cpu_index;
        u32 lo, hi, ratio, freq_id, freq;
+       unsigned long res;
+       int cpu_index;
 
        cpu_index = match_cpu(boot_cpu_data.x86, boot_cpu_data.x86_model);
        if (cpu_index < 0)
-               return -1;
-
-       *fast_calibrate = 0;
+               return 0;
 
        if (freq_desc_tables[cpu_index].msr_plat) {
                rdmsr(MSR_PLATFORM_INFO, lo, hi);
@@ -103,7 +100,7 @@ int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
        pr_info("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio);
 
        if (!ratio)
-               return 0;
+               goto fail;
 
        /* Get FSB FREQ ID */
        rdmsr(MSR_FSB_FREQ, lo, hi);
@@ -112,16 +109,19 @@ int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
        pr_info("Resolved frequency ID: %u, frequency: %u KHz\n",
                                freq_id, freq);
        if (!freq)
-               return 0;
+               goto fail;
 
        /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
-       *fast_calibrate = freq * ratio;
-       pr_info("TSC runs at %lu KHz\n", *fast_calibrate);
+       res = freq * ratio;
+       pr_info("TSC runs at %lu KHz\n", res);
 
 #ifdef CONFIG_X86_LOCAL_APIC
        lapic_timer_frequency = (freq * 1000) / HZ;
        pr_info("lapic_timer_frequency = %d\n", lapic_timer_frequency);
 #endif
+       return res;
 
-       return 1;
+fail:
+       pr_warn("Fast TSC calibration using MSR failed\n");
+       return 0;
 }
index e50425d0f5f792c1c940f85cd66e890e5fa3a6ac..9b531351a5876835e3dda6527571383a7fbae751 100644 (file)
@@ -2672,6 +2672,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
                        break;
                }
 
+               drop_large_spte(vcpu, iterator.sptep);
                if (!is_shadow_present_pte(*iterator.sptep)) {
                        u64 base_addr = iterator.addr;
 
index e81df8fce0275781a654f356fe77e38129d5210a..2de1bc09a8d40a0508e7e364bc1de301215cc7c5 100644 (file)
@@ -3002,10 +3002,8 @@ static int cr8_write_interception(struct vcpu_svm *svm)
        u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
        /* instruction emulation calls kvm_set_cr8() */
        r = cr_interception(svm);
-       if (irqchip_in_kernel(svm->vcpu.kvm)) {
-               clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+       if (irqchip_in_kernel(svm->vcpu.kvm))
                return r;
-       }
        if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
                return r;
        kvm_run->exit_reason = KVM_EXIT_SET_TPR;
@@ -3567,6 +3565,8 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
        if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK))
                return;
 
+       clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+
        if (irr == -1)
                return;
 
index a06f101ef64b4ae43e954319bbaa81a5c24c326b..3927528347510bb137e8420f4e26b07d09055483 100644 (file)
@@ -6688,7 +6688,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
                else if (is_page_fault(intr_info))
                        return enable_ept;
                else if (is_no_device(intr_info) &&
-                        !(nested_read_cr0(vmcs12) & X86_CR0_TS))
+                        !(vmcs12->guest_cr0 & X86_CR0_TS))
                        return 0;
                return vmcs12->exception_bitmap &
                                (1u << (intr_info & INTR_INFO_VECTOR_MASK));
index 39c28f09dfd5f03ca064be4bb5cfa01eb0d673a4..2b8578432d5bccd296fa6d5859e3575c0fe4aa02 100644 (file)
@@ -6186,7 +6186,7 @@ static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
                frag->len -= len;
        }
 
-       if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) {
+       if (vcpu->mmio_cur_fragment >= vcpu->mmio_nr_fragments) {
                vcpu->mmio_needed = 0;
 
                /* FIXME: return into emulator if single-stepping.  */
index 6dea040cc3a1d794c60466fb9e78eaa552b8806e..a10c8c79216187d2faa5add449762710d51c759b 100644 (file)
@@ -1020,13 +1020,17 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs)
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
+ *
+ * This function must have noinline because both callers
+ * {,trace_}do_page_fault() have notrace on. Having this an actual function
+ * guarantees there's a function trace entry.
  */
-static void __kprobes
-__do_page_fault(struct pt_regs *regs, unsigned long error_code)
+static void __kprobes noinline
+__do_page_fault(struct pt_regs *regs, unsigned long error_code,
+               unsigned long address)
 {
        struct vm_area_struct *vma;
        struct task_struct *tsk;
-       unsigned long address;
        struct mm_struct *mm;
        int fault;
        unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
@@ -1034,9 +1038,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
        tsk = current;
        mm = tsk->mm;
 
-       /* Get the faulting address: */
-       address = read_cr2();
-
        /*
         * Detect and handle instructions that would cause a page fault for
         * both a tracked kernel page and a userspace page.
@@ -1248,32 +1249,50 @@ good_area:
        up_read(&mm->mmap_sem);
 }
 
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
 do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
+       unsigned long address = read_cr2(); /* Get the faulting address */
        enum ctx_state prev_state;
 
+       /*
+        * We must have this function tagged with __kprobes, notrace and call
+        * read_cr2() before calling anything else. To avoid calling any kind
+        * of tracing machinery before we've observed the CR2 value.
+        *
+        * exception_{enter,exit}() contain all sorts of tracepoints.
+        */
+
        prev_state = exception_enter();
-       __do_page_fault(regs, error_code);
+       __do_page_fault(regs, error_code, address);
        exception_exit(prev_state);
 }
 
-static void trace_page_fault_entries(struct pt_regs *regs,
+#ifdef CONFIG_TRACING
+static void trace_page_fault_entries(unsigned long address, struct pt_regs *regs,
                                     unsigned long error_code)
 {
        if (user_mode(regs))
-               trace_page_fault_user(read_cr2(), regs, error_code);
+               trace_page_fault_user(address, regs, error_code);
        else
-               trace_page_fault_kernel(read_cr2(), regs, error_code);
+               trace_page_fault_kernel(address, regs, error_code);
 }
 
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
 trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
+       /*
+        * The exception_enter and tracepoint processing could
+        * trigger another page faults (user space callchain
+        * reading) and destroy the original cr2 value, so read
+        * the faulting address now.
+        */
+       unsigned long address = read_cr2();
        enum ctx_state prev_state;
 
        prev_state = exception_enter();
-       trace_page_fault_entries(regs, error_code);
-       __do_page_fault(regs, error_code);
+       trace_page_fault_entries(address, regs, error_code);
+       __do_page_fault(regs, error_code, address);
        exception_exit(prev_state);
 }
+#endif /* CONFIG_TRACING */
index 877b9a1b21523183d06973b60a9beb2459fff895..01495755701bd3d068db95df291ef71096d9cf33 100644 (file)
@@ -140,7 +140,7 @@ bpf_slow_path_byte_msh:
        push    %r9;                                            \
        push    SKBDATA;                                        \
 /* rsi already has offset */                                   \
-       mov     $SIZE,%ecx;     /* size */                      \
+       mov     $SIZE,%edx;     /* size */                      \
        call    bpf_internal_load_pointer_neg_helper;           \
        test    %rax,%rax;                                      \
        pop     SKBDATA;                                        \
index 1a201ac7cef8a1f7f4ce5cff2a8f8dbc6b540c00..b97acecf3fd95667e2b67bba8f88bb80428480bb 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/tlbflush.h>
 #include <asm/x86_init.h>
 #include <asm/rtc.h>
+#include <asm/uv/uv.h>
 
 #define EFI_DEBUG
 
@@ -1210,3 +1211,22 @@ static int __init parse_efi_cmdline(char *str)
        return 0;
 }
 early_param("efi", parse_efi_cmdline);
+
+void __init efi_apply_memmap_quirks(void)
+{
+       /*
+        * Once setup is done earlier, unmap the EFI memory map on mismatched
+        * firmware/kernel architectures since there is no support for runtime
+        * services.
+        */
+       if (!efi_is_native()) {
+               pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
+               efi_unmap_memmap();
+       }
+
+       /*
+        * UV doesn't support the new EFI pagetable mapping yet.
+        */
+       if (is_uv_system())
+               set_bit(EFI_OLD_MEMMAP, &x86_efi_facility);
+}
index 7d01b8c56c0029a59aa9b5b9e33036728ea7c77e..cc04e67bfd0589966e1c4b4b2fa29079c439ae24 100644 (file)
 #define smp_rmb()      barrier()
 #endif /* CONFIG_X86_PPRO_FENCE */
 
-#ifdef CONFIG_X86_OOSTORE
-#define smp_wmb()      wmb()
-#else /* CONFIG_X86_OOSTORE */
 #define smp_wmb()      barrier()
-#endif /* CONFIG_X86_OOSTORE */
 
 #define smp_read_barrier_depends()     read_barrier_depends()
 #define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
index ba56e11cbf77697f4e972fadd7dd3281f07d4376..c87ae7c6e5f94636ab576a649ada006b4fb376dc 100644 (file)
@@ -20,6 +20,7 @@ config XTENSA
        select HAVE_FUNCTION_TRACER
        select HAVE_IRQ_TIME_ACCOUNTING
        select HAVE_PERF_EVENTS
+       select COMMON_CLK
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
          primarily for embedded systems.  These processors are both
@@ -80,7 +81,6 @@ choice
 config XTENSA_VARIANT_FSF
        bool "fsf - default (not generic) configuration"
        select MMU
-       select HAVE_XTENSA_GPIO32
 
 config XTENSA_VARIANT_DC232B
        bool "dc232b - Diamond 232L Standard Core Rev.B (LE)"
@@ -135,7 +135,6 @@ config HAVE_SMP
 config SMP
        bool "Enable Symmetric multi-processing support"
        depends on HAVE_SMP
-       select USE_GENERIC_SMP_HELPERS
        select GENERIC_SMP_IDLE_THREAD
        help
          Enabled SMP Software; allows more than one CPU/CORE
index 46b4f5eab421badbec1ae38cab4afac88fb7c731..e7370b11348e8d06c113d420704664740dbdec9b 100644 (file)
                interrupt-controller;
        };
 
+       clocks {
+               osc: main-oscillator {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+               };
+       };
+
        serial0: serial@fd050020 {
                device_type = "serial";
                compatible = "ns16550a";
@@ -42,9 +49,7 @@
                reg = <0xfd050020 0x20>;
                reg-shift = <2>;
                interrupts = <0 1>; /* external irq 0 */
-               /* Filled in by platform_setup from FPGA register
-                * clock-frequency = <100000000>;
-                */
+               clocks = <&osc>;
        };
 
        enet0: ethoc@fd030000 {
@@ -52,5 +57,6 @@
                reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
                interrupts = <1 1>; /* external irq 1 */
                local-mac-address = [00 50 c2 13 6f 00];
+               clocks = <&osc>;
        };
 };
index 2a042d430c253b7dae704633727f0eabc0d5fc91..74944207167eccfb0f6e122ad7418d5728d4a2b7 100644 (file)
@@ -25,7 +25,7 @@
 
 #ifdef CONFIG_MMU
 
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
 extern unsigned long xtensa_kio_paddr;
 
 static inline unsigned long xtensa_get_kio_paddr(void)
index 8c194f6af45e09932976b3f71d8d70a8f556488f..677bfcf4ee5ddab2207ed0e5f2885b4accd29f16 100644 (file)
@@ -23,25 +23,37 @@ void secondary_trap_init(void);
 
 static inline void spill_registers(void)
 {
-
+#if XCHAL_NUM_AREGS > 16
        __asm__ __volatile__ (
-               "movi   a14, "__stringify((1 << PS_EXCM_BIT) | LOCKLEVEL)"\n\t"
-               "mov    a12, a0\n\t"
-               "rsr    a13, sar\n\t"
-               "xsr    a14, ps\n\t"
-               "movi   a0, _spill_registers\n\t"
-               "rsync\n\t"
-               "callx0 a0\n\t"
-               "mov    a0, a12\n\t"
-               "wsr    a13, sar\n\t"
-               "wsr    a14, ps\n\t"
-               : :
-#if defined(CONFIG_FRAME_POINTER)
-               : "a2", "a3", "a4",       "a11", "a12", "a13", "a14", "a15",
+               "       call12  1f\n"
+               "       _j      2f\n"
+               "       retw\n"
+               "       .align  4\n"
+               "1:\n"
+               "       _entry  a1, 48\n"
+               "       addi    a12, a0, 3\n"
+#if XCHAL_NUM_AREGS > 32
+               "       .rept   (" __stringify(XCHAL_NUM_AREGS) " - 32) / 12\n"
+               "       _entry  a1, 48\n"
+               "       mov     a12, a0\n"
+               "       .endr\n"
+#endif
+               "       _entry  a1, 48\n"
+#if XCHAL_NUM_AREGS % 12 == 0
+               "       mov     a8, a8\n"
+#elif XCHAL_NUM_AREGS % 12 == 4
+               "       mov     a12, a12\n"
+#elif XCHAL_NUM_AREGS % 12 == 8
+               "       mov     a4, a4\n"
+#endif
+               "       retw\n"
+               "2:\n"
+               : : : "a12", "a13", "memory");
 #else
-               : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15",
+       __asm__ __volatile__ (
+               "       mov     a12, a12\n"
+               : : : "memory");
 #endif
-                 "memory");
 }
 
 #endif /* _XTENSA_TRAPS_H */
index 5791b45d5a5d5b25f97f9d7d5ee8e05b80ace6cb..f74ddfbb92ef56587b618db2a7e80a2c96593499 100644 (file)
@@ -25,7 +25,7 @@
 #define XCHAL_KIO_DEFAULT_PADDR                0xf0000000
 #define XCHAL_KIO_SIZE                 0x10000000
 
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
 #define XCHAL_KIO_PADDR                        xtensa_get_kio_paddr()
 #else
 #define XCHAL_KIO_PADDR                        XCHAL_KIO_DEFAULT_PADDR
index 51940fec6990f2b9a1c86fa5c43a199c3eade2f0..b9395529f02d465643091d71c4d6b6ca9650ff4b 100644 (file)
@@ -734,7 +734,12 @@ __SYSCALL(332, sys_finit_module, 3)
 #define __NR_accept4                           333
 __SYSCALL(333, sys_accept4, 4)
 
-#define __NR_syscall_count                     334
+#define __NR_sched_setattr                     334
+__SYSCALL(334, sys_sched_setattr, 2)
+#define __NR_sched_getattr                     335
+__SYSCALL(335, sys_sched_getattr, 3)
+
+#define __NR_syscall_count                     336
 
 /*
  * sysxtensa syscall handler
index 21dbe6bdb8edc661d729f656a02a5f1cf01a18c1..ef7f4990722b4fde3a175a0d524f82c3b2ce8b7b 100644 (file)
@@ -1081,196 +1081,53 @@ ENTRY(fast_syscall_spill_registers)
 
        rsr     a0, sar
        s32i    a3, a2, PT_AREG3
-       s32i    a4, a2, PT_AREG4
-       s32i    a0, a2, PT_AREG5        # store SAR to PT_AREG5
+       s32i    a0, a2, PT_SAR
 
-       /* The spill routine might clobber a7, a11, and a15. */
+       /* The spill routine might clobber a4, a7, a8, a11, a12, and a15. */
 
+       s32i    a4, a2, PT_AREG4
        s32i    a7, a2, PT_AREG7
+       s32i    a8, a2, PT_AREG8
        s32i    a11, a2, PT_AREG11
+       s32i    a12, a2, PT_AREG12
        s32i    a15, a2, PT_AREG15
 
-       call0   _spill_registers        # destroys a3, a4, and SAR
-
-       /* Advance PC, restore registers and SAR, and return from exception. */
-
-       l32i    a3, a2, PT_AREG5
-       l32i    a4, a2, PT_AREG4
-       l32i    a0, a2, PT_AREG0
-       wsr     a3, sar
-       l32i    a3, a2, PT_AREG3
-
-       /* Restore clobbered registers. */
-
-       l32i    a7, a2, PT_AREG7
-       l32i    a11, a2, PT_AREG11
-       l32i    a15, a2, PT_AREG15
-
-       movi    a2, 0
-       rfe
-
-ENDPROC(fast_syscall_spill_registers)
-
-/* Fixup handler.
- *
- * We get here if the spill routine causes an exception, e.g. tlb miss.
- * We basically restore WINDOWBASE and WINDOWSTART to the condition when
- * we entered the spill routine and jump to the user exception handler.
- *
- * a0: value of depc, original value in depc
- * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
- * a3: exctable, original value in excsave1
- */
-
-ENTRY(fast_syscall_spill_registers_fixup)
-
-       rsr     a2, windowbase  # get current windowbase (a2 is saved)
-       xsr     a0, depc        # restore depc and a0
-       ssl     a2              # set shift (32 - WB)
-
-       /* We need to make sure the current registers (a0-a3) are preserved.
-        * To do this, we simply set the bit for the current window frame
-        * in WS, so that the exception handlers save them to the task stack.
-        */
-
-       xsr     a3, excsave1    # get spill-mask
-       slli    a3, a3, 1       # shift left by one
-
-       slli    a2, a3, 32-WSBITS
-       src     a2, a3, a2      # a2 = xxwww1yyxxxwww1yy......
-       wsr     a2, windowstart # set corrected windowstart
-
-       srli    a3, a3, 1
-       rsr     a2, excsave1
-       l32i    a2, a2, EXC_TABLE_DOUBLE_SAVE   # restore a2
-       xsr     a2, excsave1
-       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE   # save a3
-       l32i    a3, a2, EXC_TABLE_PARAM # original WB (in user task)
-       xsr     a2, excsave1
-
-       /* Return to the original (user task) WINDOWBASE.
-        * We leave the following frame behind:
-        * a0, a1, a2   same
-        * a3:          trashed (saved in EXC_TABLE_DOUBLE_SAVE)
-        * depc:        depc (we have to return to that address)
-        * excsave_1:   exctable
-        */
-
-       wsr     a3, windowbase
-       rsync
-
-       /* We are now in the original frame when we entered _spill_registers:
-        *  a0: return address
-        *  a1: used, stack pointer
-        *  a2: kernel stack pointer
-        *  a3: available
-        *  depc: exception address
-        *  excsave: exctable
-        * Note: This frame might be the same as above.
-        */
-
-       /* Setup stack pointer. */
-
-       addi    a2, a2, -PT_USER_SIZE
-       s32i    a0, a2, PT_AREG0
-
-       /* Make sure we return to this fixup handler. */
-
-       movi    a3, fast_syscall_spill_registers_fixup_return
-       s32i    a3, a2, PT_DEPC         # setup depc
-
-       /* Jump to the exception handler. */
-
-       rsr     a3, excsave1
-       rsr     a0, exccause
-       addx4   a0, a0, a3                      # find entry in table
-       l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
-       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
-       jx      a0
-
-ENDPROC(fast_syscall_spill_registers_fixup)
-
-ENTRY(fast_syscall_spill_registers_fixup_return)
-
-       /* When we return here, all registers have been restored (a2: DEPC) */
-
-       wsr     a2, depc                # exception address
-
-       /* Restore fixup handler. */
-
-       rsr     a2, excsave1
-       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE
-       movi    a3, fast_syscall_spill_registers_fixup
-       s32i    a3, a2, EXC_TABLE_FIXUP
-       rsr     a3, windowbase
-       s32i    a3, a2, EXC_TABLE_PARAM
-       l32i    a2, a2, EXC_TABLE_KSTK
-
-       /* Load WB at the time the exception occurred. */
-
-       rsr     a3, sar                 # WB is still in SAR
-       neg     a3, a3
-       wsr     a3, windowbase
-       rsync
-
-       rsr     a3, excsave1
-       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
-
-       rfde
-
-ENDPROC(fast_syscall_spill_registers_fixup_return)
-
-/*
- * spill all registers.
- *
- * This is not a real function. The following conditions must be met:
- *
- *  - must be called with call0.
- *  - uses a3, a4 and SAR.
- *  - the last 'valid' register of each frame are clobbered.
- *  - the caller must have registered a fixup handler
- *    (or be inside a critical section)
- *  - PS_EXCM must be set (PS_WOE cleared?)
- */
-
-ENTRY(_spill_registers)
-
        /*
         * Rotate ws so that the current windowbase is at bit 0.
         * Assume ws = xxxwww1yy (www1 current window frame).
         * Rotate ws right so that a4 = yyxxxwww1.
         */
 
-       rsr     a4, windowbase
+       rsr     a0, windowbase
        rsr     a3, windowstart         # a3 = xxxwww1yy
-       ssr     a4                      # holds WB
-       slli    a4, a3, WSBITS
-       or      a3, a3, a4              # a3 = xxxwww1yyxxxwww1yy
+       ssr     a0                      # holds WB
+       slli    a0, a3, WSBITS
+       or      a3, a3, a0              # a3 = xxxwww1yyxxxwww1yy
        srl     a3, a3                  # a3 = 00xxxwww1yyxxxwww1
 
        /* We are done if there are no more than the current register frame. */
 
        extui   a3, a3, 1, WSBITS-1     # a3 = 0yyxxxwww
-       movi    a4, (1 << (WSBITS-1))
+       movi    a0, (1 << (WSBITS-1))
        _beqz   a3, .Lnospill           # only one active frame? jump
 
        /* We want 1 at the top, so that we return to the current windowbase */
 
-       or      a3, a3, a4              # 1yyxxxwww
+       or      a3, a3, a0              # 1yyxxxwww
 
        /* Skip empty frames - get 'oldest' WINDOWSTART-bit. */
 
        wsr     a3, windowstart         # save shifted windowstart
-       neg     a4, a3
-       and     a3, a4, a3              # first bit set from right: 000010000
+       neg     a0, a3
+       and     a3, a0, a3              # first bit set from right: 000010000
 
-       ffs_ws  a4, a3                  # a4: shifts to skip empty frames
+       ffs_ws  a0, a3                  # a0: shifts to skip empty frames
        movi    a3, WSBITS
-       sub     a4, a3, a4              # WSBITS-a4:number of 0-bits from right
-       ssr     a4                      # save in SAR for later.
+       sub     a0, a3, a0              # WSBITS-a0:number of 0-bits from right
+       ssr     a0                      # save in SAR for later.
 
        rsr     a3, windowbase
-       add     a3, a3, a4
+       add     a3, a3, a0
        wsr     a3, windowbase
        rsync
 
@@ -1285,22 +1142,6 @@ ENTRY(_spill_registers)
         * we have to save 4,8. or 12 registers.
         */
 
-       _bbsi.l a3, 1, .Lc4
-       _bbsi.l a3, 2, .Lc8
-
-       /* Special case: we have a call12-frame starting at a4. */
-
-       _bbci.l a3, 3, .Lc12    # bit 3 shouldn't be zero! (Jump to Lc12 first)
-
-       s32e    a4, a1, -16     # a1 is valid with an empty spill area
-       l32e    a4, a5, -12
-       s32e    a8, a4, -48
-       mov     a8, a4
-       l32e    a4, a1, -16
-       j       .Lc12c
-
-.Lnospill:
-       ret
 
 .Lloop: _bbsi.l        a3, 1, .Lc4
        _bbci.l a3, 2, .Lc12
@@ -1314,20 +1155,10 @@ ENTRY(_spill_registers)
        s32e    a9, a4, -28
        s32e    a10, a4, -24
        s32e    a11, a4, -20
-
        srli    a11, a3, 2              # shift windowbase by 2
        rotw    2
        _bnei   a3, 1, .Lloop
-
-.Lexit: /* Done. Do the final rotation, set WS, and return. */
-
-       rotw    1
-       rsr     a3, windowbase
-       ssl     a3
-       movi    a3, 1
-       sll     a3, a3
-       wsr     a3, windowstart
-       ret
+       j       .Lexit
 
 .Lc4:  s32e    a4, a9, -16
        s32e    a5, a9, -12
@@ -1343,11 +1174,11 @@ ENTRY(_spill_registers)
 
        /* 12-register frame (call12) */
 
-       l32e    a2, a5, -12
-       s32e    a8, a2, -48
-       mov     a8, a2
+       l32e    a0, a5, -12
+       s32e    a8, a0, -48
+       mov     a8, a0
 
-.Lc12c: s32e   a9, a8, -44
+       s32e    a9, a8, -44
        s32e    a10, a8, -40
        s32e    a11, a8, -36
        s32e    a12, a8, -32
@@ -1367,30 +1198,54 @@ ENTRY(_spill_registers)
         */
 
        rotw    1
-       mov     a5, a13
+       mov     a4, a13
        rotw    -1
 
-       s32e    a4, a9, -16
-       s32e    a5, a9, -12
-       s32e    a6, a9, -8
-       s32e    a7, a9, -4
+       s32e    a4, a8, -16
+       s32e    a5, a8, -12
+       s32e    a6, a8, -8
+       s32e    a7, a8, -4
 
        rotw    3
 
        _beqi   a3, 1, .Lexit
        j       .Lloop
 
-.Linvalid_mask:
+.Lexit:
 
-       /* We get here because of an unrecoverable error in the window
-        * registers. If we are in user space, we kill the application,
-        * however, this condition is unrecoverable in kernel space.
-        */
+       /* Done. Do the final rotation and set WS */
+
+       rotw    1
+       rsr     a3, windowbase
+       ssl     a3
+       movi    a3, 1
+       sll     a3, a3
+       wsr     a3, windowstart
+.Lnospill:
+
+       /* Advance PC, restore registers and SAR, and return from exception. */
+
+       l32i    a3, a2, PT_SAR
+       l32i    a0, a2, PT_AREG0
+       wsr     a3, sar
+       l32i    a3, a2, PT_AREG3
 
-       rsr     a0, ps
-       _bbci.l a0, PS_UM_BIT, 1f
+       /* Restore clobbered registers. */
 
-       /* User space: Setup a dummy frame and kill application.
+       l32i    a4, a2, PT_AREG4
+       l32i    a7, a2, PT_AREG7
+       l32i    a8, a2, PT_AREG8
+       l32i    a11, a2, PT_AREG11
+       l32i    a12, a2, PT_AREG12
+       l32i    a15, a2, PT_AREG15
+
+       movi    a2, 0
+       rfe
+
+.Linvalid_mask:
+
+       /* We get here because of an unrecoverable error in the window
+        * registers, so set up a dummy frame and kill the user application.
         * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
         */
 
@@ -1414,14 +1269,136 @@ ENTRY(_spill_registers)
        movi    a4, do_exit
        callx4  a4
 
-1:     /* Kernel space: PANIC! */
+       /* shouldn't return, so panic */
 
        wsr     a0, excsave1
        movi    a0, unrecoverable_exception
        callx0  a0              # should not return
 1:     j       1b
 
-ENDPROC(_spill_registers)
+
+ENDPROC(fast_syscall_spill_registers)
+
+/* Fixup handler.
+ *
+ * We get here if the spill routine causes an exception, e.g. tlb miss.
+ * We basically restore WINDOWBASE and WINDOWSTART to the condition when
+ * we entered the spill routine and jump to the user exception handler.
+ *
+ * Note that we only need to restore the bits in windowstart that have not
+ * been spilled yet by the _spill_register routine. Luckily, a3 contains a
+ * rotated windowstart with only those bits set for frames that haven't been
+ * spilled yet. Because a3 is rotated such that bit 0 represents the register
+ * frame for the current windowbase - 1, we need to rotate a3 left by the
+ * value of the current windowbase + 1 and move it to windowstart.
+ *
+ * a0: value of depc, original value in depc
+ * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
+ * a3: exctable, original value in excsave1
+ */
+
+ENTRY(fast_syscall_spill_registers_fixup)
+
+       rsr     a2, windowbase  # get current windowbase (a2 is saved)
+       xsr     a0, depc        # restore depc and a0
+       ssl     a2              # set shift (32 - WB)
+
+       /* We need to make sure the current registers (a0-a3) are preserved.
+        * To do this, we simply set the bit for the current window frame
+        * in WS, so that the exception handlers save them to the task stack.
+        *
+        * Note: we use a3 to set the windowbase, so we take a special care
+        * of it, saving it in the original _spill_registers frame across
+        * the exception handler call.
+        */
+
+       xsr     a3, excsave1    # get spill-mask
+       slli    a3, a3, 1       # shift left by one
+       addi    a3, a3, 1       # set the bit for the current window frame
+
+       slli    a2, a3, 32-WSBITS
+       src     a2, a3, a2      # a2 = xxwww1yyxxxwww1yy......
+       wsr     a2, windowstart # set corrected windowstart
+
+       srli    a3, a3, 1
+       rsr     a2, excsave1
+       l32i    a2, a2, EXC_TABLE_DOUBLE_SAVE   # restore a2
+       xsr     a2, excsave1
+       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE   # save a3
+       l32i    a3, a2, EXC_TABLE_PARAM # original WB (in user task)
+       xsr     a2, excsave1
+
+       /* Return to the original (user task) WINDOWBASE.
+        * We leave the following frame behind:
+        * a0, a1, a2   same
+        * a3:          trashed (saved in EXC_TABLE_DOUBLE_SAVE)
+        * depc:        depc (we have to return to that address)
+        * excsave_1:   exctable
+        */
+
+       wsr     a3, windowbase
+       rsync
+
+       /* We are now in the original frame when we entered _spill_registers:
+        *  a0: return address
+        *  a1: used, stack pointer
+        *  a2: kernel stack pointer
+        *  a3: available
+        *  depc: exception address
+        *  excsave: exctable
+        * Note: This frame might be the same as above.
+        */
+
+       /* Setup stack pointer. */
+
+       addi    a2, a2, -PT_USER_SIZE
+       s32i    a0, a2, PT_AREG0
+
+       /* Make sure we return to this fixup handler. */
+
+       movi    a3, fast_syscall_spill_registers_fixup_return
+       s32i    a3, a2, PT_DEPC         # setup depc
+
+       /* Jump to the exception handler. */
+
+       rsr     a3, excsave1
+       rsr     a0, exccause
+       addx4   a0, a0, a3                      # find entry in table
+       l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
+       jx      a0
+
+ENDPROC(fast_syscall_spill_registers_fixup)
+
+ENTRY(fast_syscall_spill_registers_fixup_return)
+
+       /* When we return here, all registers have been restored (a2: DEPC) */
+
+       wsr     a2, depc                # exception address
+
+       /* Restore fixup handler. */
+
+       rsr     a2, excsave1
+       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE
+       movi    a3, fast_syscall_spill_registers_fixup
+       s32i    a3, a2, EXC_TABLE_FIXUP
+       rsr     a3, windowbase
+       s32i    a3, a2, EXC_TABLE_PARAM
+       l32i    a2, a2, EXC_TABLE_KSTK
+
+       /* Load WB at the time the exception occurred. */
+
+       rsr     a3, sar                 # WB is still in SAR
+       neg     a3, a3
+       wsr     a3, windowbase
+       rsync
+
+       rsr     a3, excsave1
+       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
+
+       rfde
+
+ENDPROC(fast_syscall_spill_registers_fixup_return)
 
 #ifdef CONFIG_MMU
 /*
@@ -1794,6 +1771,43 @@ ENTRY(system_call)
 
 ENDPROC(system_call)
 
+/*
+ * Spill live registers on the kernel stack macro.
+ *
+ * Entry condition: ps.woe is set, ps.excm is cleared
+ * Exit condition: windowstart has single bit set
+ * May clobber: a12, a13
+ */
+       .macro  spill_registers_kernel
+
+#if XCHAL_NUM_AREGS > 16
+       call12  1f
+       _j      2f
+       retw
+       .align  4
+1:
+       _entry  a1, 48
+       addi    a12, a0, 3
+#if XCHAL_NUM_AREGS > 32
+       .rept   (XCHAL_NUM_AREGS - 32) / 12
+       _entry  a1, 48
+       mov     a12, a0
+       .endr
+#endif
+       _entry  a1, 48
+#if XCHAL_NUM_AREGS % 12 == 0
+       mov     a8, a8
+#elif XCHAL_NUM_AREGS % 12 == 4
+       mov     a12, a12
+#elif XCHAL_NUM_AREGS % 12 == 8
+       mov     a4, a4
+#endif
+       retw
+2:
+#else
+       mov     a12, a12
+#endif
+       .endm
 
 /*
  * Task switch.
@@ -1806,21 +1820,20 @@ ENTRY(_switch_to)
 
        entry   a1, 16
 
-       mov     a12, a2                 # preserve 'prev' (a2)
-       mov     a13, a3                 # and 'next' (a3)
+       mov     a10, a2                 # preserve 'prev' (a2)
+       mov     a11, a3                 # and 'next' (a3)
 
        l32i    a4, a2, TASK_THREAD_INFO
        l32i    a5, a3, TASK_THREAD_INFO
 
-       save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+       save_xtregs_user a4 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
 
-       s32i    a0, a12, THREAD_RA      # save return address
-       s32i    a1, a12, THREAD_SP      # save stack pointer
+       s32i    a0, a10, THREAD_RA      # save return address
+       s32i    a1, a10, THREAD_SP      # save stack pointer
 
        /* Disable ints while we manipulate the stack pointer. */
 
-       movi    a14, (1 << PS_EXCM_BIT) | LOCKLEVEL
-       xsr     a14, ps
+       rsil    a14, LOCKLEVEL
        rsr     a3, excsave1
        rsync
        s32i    a3, a3, EXC_TABLE_FIXUP /* enter critical section */
@@ -1835,7 +1848,7 @@ ENTRY(_switch_to)
 
        /* Flush register file. */
 
-       call0   _spill_registers        # destroys a3, a4, and SAR
+       spill_registers_kernel
 
        /* Set kernel stack (and leave critical section)
         * Note: It's save to set it here. The stack will not be overwritten
@@ -1851,13 +1864,13 @@ ENTRY(_switch_to)
 
        /* restore context of the task 'next' */
 
-       l32i    a0, a13, THREAD_RA      # restore return address
-       l32i    a1, a13, THREAD_SP      # restore stack pointer
+       l32i    a0, a11, THREAD_RA      # restore return address
+       l32i    a1, a11, THREAD_SP      # restore stack pointer
 
-       load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+       load_xtregs_user a5 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
 
        wsr     a14, ps
-       mov     a2, a12                 # return 'prev'
+       mov     a2, a10                 # return 'prev'
        rsync
 
        retw
index 7d12af1317f183d9af4b813ba4fd11bc94450924..84fe931bb60e1f012417d202d002813b12cf68aa 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/bootmem.h>
 #include <linux/kernel.h>
 #include <linux/percpu.h>
+#include <linux/clk-provider.h>
 #include <linux/cpu.h>
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
@@ -276,6 +277,7 @@ void __init early_init_devtree(void *params)
 
 static int __init xtensa_device_probe(void)
 {
+       of_clk_init(NULL);
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
        return 0;
 }
index 08b769d3b3a1c48482179eac8c68c562f61321c4..2a1823de69ccf621b6ea63e2ad815bbe118fa2f9 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/platform.h>
 
 unsigned long ccount_freq;             /* ccount Hz */
+EXPORT_SYMBOL(ccount_freq);
 
 static cycle_t ccount_read(struct clocksource *cs)
 {
index cb8fd44caabc6d246ce7975dfc0f370d87052fc2..f9e1ec346e359c7410482c5d8dfd5a9de88bfafc 100644 (file)
@@ -235,7 +235,7 @@ ENTRY(_DoubleExceptionVector)
 
        /* Check for overflow/underflow exception, jump if overflow. */
 
-       _bbci.l a0, 6, _DoubleExceptionVector_WindowOverflow
+       bbci.l  a0, 6, _DoubleExceptionVector_WindowOverflow
 
        /*
         * Restart window underflow exception.
index 74a60c7e085ea40349336089889de2d52f9d142c..80b33ed51f31174fd41a53bebd957c140517d8f9 100644 (file)
@@ -122,9 +122,7 @@ EXPORT_SYMBOL(insw);
 EXPORT_SYMBOL(insl);
 
 extern long common_exception_return;
-extern long _spill_registers;
 EXPORT_SYMBOL(common_exception_return);
-EXPORT_SYMBOL(_spill_registers);
 
 #ifdef CONFIG_FUNCTION_TRACER
 EXPORT_SYMBOL(_mcount);
index 479d7537a32a4f8039ae02581f8644d53eb80dda..aff108df92d3a301e8ba0ccaf7e13a5fb26c9038 100644 (file)
@@ -90,7 +90,7 @@ int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
 
 
 /*
- * Initialize the bootmem system and give it all the memory we have available.
+ * Initialize the bootmem system and give it all low memory we have available.
  */
 
 void __init bootmem_init(void)
@@ -142,9 +142,14 @@ void __init bootmem_init(void)
 
        /* Add all remaining memory pieces into the bootmem map */
 
-       for (i=0; i<sysmem.nr_banks; i++)
-               free_bootmem(sysmem.bank[i].start,
-                            sysmem.bank[i].end - sysmem.bank[i].start);
+       for (i = 0; i < sysmem.nr_banks; i++) {
+               if (sysmem.bank[i].start >> PAGE_SHIFT < max_low_pfn) {
+                       unsigned long end = min(max_low_pfn << PAGE_SHIFT,
+                                               sysmem.bank[i].end);
+                       free_bootmem(sysmem.bank[i].start,
+                                    end - sysmem.bank[i].start);
+               }
+       }
 
 }
 
index 36ec171698b833ddbebb6c9e51e9f18d4c53f278..861203e958da828deb140122752e95b47ddbf35f 100644 (file)
@@ -39,7 +39,7 @@ void init_mmu(void)
        set_itlbcfg_register(0);
        set_dtlbcfg_register(0);
 #endif
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
        /*
         * Update the IO area mapping in case xtensa_kio_paddr has changed
         */
index 800227862fe8b91d561e8b318b757675a1e21f68..57fd08b36f51a151a389794bf4e8af7c9b64fd13 100644 (file)
@@ -135,11 +135,11 @@ static void __init update_local_mac(struct device_node *node)
 
 static int __init machine_setup(void)
 {
-       struct device_node *serial;
+       struct device_node *clock;
        struct device_node *eth = NULL;
 
-       for_each_compatible_node(serial, NULL, "ns16550a")
-               update_clock_frequency(serial);
+       for_each_node_by_name(clock, "main-oscillator")
+               update_clock_frequency(clock);
 
        if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
                update_local_mac(eth);
@@ -290,6 +290,7 @@ static int __init xtavnet_init(void)
         * knows whether they set it correctly on the DIP switches.
         */
        pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr);
+       ethoc_pdata.eth_clkfreq = *(long *)XTFPGA_CLKFRQ_VADDR;
 
        return 0;
 }
index bf4020116df521d18e1891d33a1815154b6046e9..244cdea4dee50252a06e41799badfb1c5c2e61a1 100644 (file)
 #define XCHAL_CP_MASK                  0x00    /* bitmask of all CPs by ID */
 #define XCHAL_CP_PORT_MASK             0x00    /* bitmask of only port CPs */
 
-/*  Basic parameters of each coprocessor:  */
-#define XCHAL_CP7_NAME                 "XTIOP"
-#define XCHAL_CP7_IDENT                        XTIOP
-#define XCHAL_CP7_SA_SIZE              0       /* size of state save area */
-#define XCHAL_CP7_SA_ALIGN             1       /* min alignment of save area */
-#define XCHAL_CP_ID_XTIOP              7       /* coprocessor ID (0..7) */
-
 /*  Filler info for unassigned coprocessors, to simplify arrays etc:  */
 #define XCHAL_NCP_SA_SIZE              0
 #define XCHAL_NCP_SA_ALIGN             1
@@ -42,6 +35,8 @@
 #define XCHAL_CP5_SA_ALIGN             1
 #define XCHAL_CP6_SA_SIZE              0
 #define XCHAL_CP6_SA_ALIGN             1
+#define XCHAL_CP7_SA_SIZE              0
+#define XCHAL_CP7_SA_ALIGN             1
 
 /*  Save area for non-coprocessor optional and custom (TIE) state:  */
 #define XCHAL_NCP_SA_SIZE              0
index 86154eab95239fdd6300ddc665f03650b80f1a5b..604f6d99ab92ca859d46b7ff7d8ce4b5519ebb61 100644 (file)
@@ -435,9 +435,9 @@ static inline uint64_t blkg_stat_read(struct blkg_stat *stat)
        uint64_t v;
 
        do {
-               start = u64_stats_fetch_begin_bh(&stat->syncp);
+               start = u64_stats_fetch_begin_irq(&stat->syncp);
                v = stat->cnt;
-       } while (u64_stats_fetch_retry_bh(&stat->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&stat->syncp, start));
 
        return v;
 }
@@ -508,9 +508,9 @@ static inline struct blkg_rwstat blkg_rwstat_read(struct blkg_rwstat *rwstat)
        struct blkg_rwstat tmp;
 
        do {
-               start = u64_stats_fetch_begin_bh(&rwstat->syncp);
+               start = u64_stats_fetch_begin_irq(&rwstat->syncp);
                tmp = *rwstat;
-       } while (u64_stats_fetch_retry_bh(&rwstat->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&rwstat->syncp, start));
 
        return tmp;
 }
index c68613bb4c79b718b87dd5dc90b3a8cdd307c3fc..dbf4502b1d6779eadd1573f28f75def4e26a031a 100644 (file)
@@ -65,7 +65,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
         * be resued after dying flag is set
         */
        if (q->mq_ops) {
-               blk_mq_insert_request(q, rq, at_head, true);
+               blk_mq_insert_request(rq, at_head, true, false);
                return;
        }
 
index 66e2b697f5db1299b20d8018232fbcd191b279b8..f598f794c3c679e8c7904bb88284c96434123d66 100644 (file)
@@ -137,7 +137,7 @@ static void mq_flush_run(struct work_struct *work)
        rq = container_of(work, struct request, mq_flush_work);
 
        memset(&rq->csd, 0, sizeof(rq->csd));
-       blk_mq_run_request(rq, true, false);
+       blk_mq_insert_request(rq, false, true, false);
 }
 
 static bool blk_flush_queue_rq(struct request *rq)
@@ -411,7 +411,7 @@ void blk_insert_flush(struct request *rq)
        if ((policy & REQ_FSEQ_DATA) &&
            !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
                if (q->mq_ops) {
-                       blk_mq_run_request(rq, false, true);
+                       blk_mq_insert_request(rq, false, false, true);
                } else
                        list_add_tail(&rq->queuelist, &q->queue_head);
                return;
index 3146befb56aaac7b925428d0afee89c9e083094a..136ef8643bbade3dd2d5d84e35183c749bc00399 100644 (file)
@@ -11,7 +11,7 @@
 #include "blk-mq.h"
 
 static LIST_HEAD(blk_mq_cpu_notify_list);
-static DEFINE_SPINLOCK(blk_mq_cpu_notify_lock);
+static DEFINE_RAW_SPINLOCK(blk_mq_cpu_notify_lock);
 
 static int blk_mq_main_cpu_notify(struct notifier_block *self,
                                  unsigned long action, void *hcpu)
@@ -19,12 +19,12 @@ static int blk_mq_main_cpu_notify(struct notifier_block *self,
        unsigned int cpu = (unsigned long) hcpu;
        struct blk_mq_cpu_notifier *notify;
 
-       spin_lock(&blk_mq_cpu_notify_lock);
+       raw_spin_lock(&blk_mq_cpu_notify_lock);
 
        list_for_each_entry(notify, &blk_mq_cpu_notify_list, list)
                notify->notify(notify->data, action, cpu);
 
-       spin_unlock(&blk_mq_cpu_notify_lock);
+       raw_spin_unlock(&blk_mq_cpu_notify_lock);
        return NOTIFY_OK;
 }
 
@@ -32,16 +32,16 @@ void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
 {
        BUG_ON(!notifier->notify);
 
-       spin_lock(&blk_mq_cpu_notify_lock);
+       raw_spin_lock(&blk_mq_cpu_notify_lock);
        list_add_tail(&notifier->list, &blk_mq_cpu_notify_list);
-       spin_unlock(&blk_mq_cpu_notify_lock);
+       raw_spin_unlock(&blk_mq_cpu_notify_lock);
 }
 
 void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
 {
-       spin_lock(&blk_mq_cpu_notify_lock);
+       raw_spin_lock(&blk_mq_cpu_notify_lock);
        list_del(&notifier->list);
-       spin_unlock(&blk_mq_cpu_notify_lock);
+       raw_spin_unlock(&blk_mq_cpu_notify_lock);
 }
 
 void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
index 1fa9dd153fde22a976483ef3b5da3ec39f0f458e..883f7208901585ab1ee02891a3ad5b67599a4243 100644 (file)
@@ -73,8 +73,8 @@ static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx,
                set_bit(ctx->index_hw, hctx->ctx_map);
 }
 
-static struct request *blk_mq_alloc_rq(struct blk_mq_hw_ctx *hctx, gfp_t gfp,
-                                      bool reserved)
+static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
+                                             gfp_t gfp, bool reserved)
 {
        struct request *rq;
        unsigned int tag;
@@ -193,12 +193,6 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
        ctx->rq_dispatched[rw_is_sync(rw_flags)]++;
 }
 
-static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
-                                             gfp_t gfp, bool reserved)
-{
-       return blk_mq_alloc_rq(hctx, gfp, reserved);
-}
-
 static struct request *blk_mq_alloc_request_pinned(struct request_queue *q,
                                                   int rw, gfp_t gfp,
                                                   bool reserved)
@@ -289,38 +283,10 @@ void blk_mq_free_request(struct request *rq)
        __blk_mq_free_request(hctx, ctx, rq);
 }
 
-static void blk_mq_bio_endio(struct request *rq, struct bio *bio, int error)
-{
-       if (error)
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
-       else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
-               error = -EIO;
-
-       if (unlikely(rq->cmd_flags & REQ_QUIET))
-               set_bit(BIO_QUIET, &bio->bi_flags);
-
-       /* don't actually finish bio if it's part of flush sequence */
-       if (!(rq->cmd_flags & REQ_FLUSH_SEQ))
-               bio_endio(bio, error);
-}
-
-void blk_mq_end_io(struct request *rq, int error)
+bool blk_mq_end_io_partial(struct request *rq, int error, unsigned int nr_bytes)
 {
-       struct bio *bio = rq->bio;
-       unsigned int bytes = 0;
-
-       trace_block_rq_complete(rq->q, rq);
-
-       while (bio) {
-               struct bio *next = bio->bi_next;
-
-               bio->bi_next = NULL;
-               bytes += bio->bi_iter.bi_size;
-               blk_mq_bio_endio(rq, bio, error);
-               bio = next;
-       }
-
-       blk_account_io_completion(rq, bytes);
+       if (blk_update_request(rq, error, blk_rq_bytes(rq)))
+               return true;
 
        blk_account_io_done(rq);
 
@@ -328,8 +294,9 @@ void blk_mq_end_io(struct request *rq, int error)
                rq->end_io(rq, error);
        else
                blk_mq_free_request(rq);
+       return false;
 }
-EXPORT_SYMBOL(blk_mq_end_io);
+EXPORT_SYMBOL(blk_mq_end_io_partial);
 
 static void __blk_mq_complete_request_remote(void *data)
 {
@@ -730,60 +697,27 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
        blk_mq_add_timer(rq);
 }
 
-void blk_mq_insert_request(struct request_queue *q, struct request *rq,
-                          bool at_head, bool run_queue)
+void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
+               bool async)
 {
+       struct request_queue *q = rq->q;
        struct blk_mq_hw_ctx *hctx;
-       struct blk_mq_ctx *ctx, *current_ctx;
+       struct blk_mq_ctx *ctx = rq->mq_ctx, *current_ctx;
+
+       current_ctx = blk_mq_get_ctx(q);
+       if (!cpu_online(ctx->cpu))
+               rq->mq_ctx = ctx = current_ctx;
 
-       ctx = rq->mq_ctx;
        hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
-       if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
+       if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA) &&
+           !(rq->cmd_flags & (REQ_FLUSH_SEQ))) {
                blk_insert_flush(rq);
        } else {
-               current_ctx = blk_mq_get_ctx(q);
-
-               if (!cpu_online(ctx->cpu)) {
-                       ctx = current_ctx;
-                       hctx = q->mq_ops->map_queue(q, ctx->cpu);
-                       rq->mq_ctx = ctx;
-               }
                spin_lock(&ctx->lock);
                __blk_mq_insert_request(hctx, rq, at_head);
                spin_unlock(&ctx->lock);
-
-               blk_mq_put_ctx(current_ctx);
-       }
-
-       if (run_queue)
-               __blk_mq_run_hw_queue(hctx);
-}
-EXPORT_SYMBOL(blk_mq_insert_request);
-
-/*
- * This is a special version of blk_mq_insert_request to bypass FLUSH request
- * check. Should only be used internally.
- */
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async)
-{
-       struct request_queue *q = rq->q;
-       struct blk_mq_hw_ctx *hctx;
-       struct blk_mq_ctx *ctx, *current_ctx;
-
-       current_ctx = blk_mq_get_ctx(q);
-
-       ctx = rq->mq_ctx;
-       if (!cpu_online(ctx->cpu)) {
-               ctx = current_ctx;
-               rq->mq_ctx = ctx;
        }
-       hctx = q->mq_ops->map_queue(q, ctx->cpu);
-
-       /* ctx->cpu might be offline */
-       spin_lock(&ctx->lock);
-       __blk_mq_insert_request(hctx, rq, false);
-       spin_unlock(&ctx->lock);
 
        blk_mq_put_ctx(current_ctx);
 
@@ -926,6 +860,8 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
        ctx = blk_mq_get_ctx(q);
        hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
+       if (is_sync)
+               rw |= REQ_SYNC;
        trace_block_getrq(q, bio, rw);
        rq = __blk_mq_alloc_request(hctx, GFP_ATOMIC, false);
        if (likely(rq))
index ed0035cd458ee8f78691a8f95415a8665707ca11..72beba1f9d55efa827e8667535a7f2956dd2b924 100644 (file)
@@ -23,7 +23,6 @@ struct blk_mq_ctx {
 };
 
 void __blk_mq_complete_request(struct request *rq);
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async);
 void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
 void blk_mq_init_flush(struct request_queue *q);
 void blk_mq_drain_queue(struct request_queue *q);
index e7515aa43d6bd62c3ec0e33fb6781d2a9f2f27a7..6f190bc2b8b784bf7e09425b77c560fa60f04b90 100644 (file)
@@ -243,6 +243,8 @@ static int acpi_ac_resume(struct device *dev)
                kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
        return 0;
 }
+#else
+#define acpi_ac_resume NULL
 #endif
 static SIMPLE_DEV_PM_OPS(acpi_ac_pm_ops, NULL, acpi_ac_resume);
 
index 018a4288370630cb40203ecd43cc2809851288ae..797a6938d0515edb7ce7e5ce3f4f1648c538e515 100644 (file)
@@ -841,6 +841,8 @@ static int acpi_battery_resume(struct device *dev)
        acpi_battery_update(battery);
        return 0;
 }
+#else
+#define acpi_battery_resume NULL
 #endif
 
 static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
index 10e4964d051a9c295e6185db1cfebe20b0ce5a9d..afec4526c48aa04e2921a199396e8fb2ea7489be 100644 (file)
@@ -260,14 +260,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        },
        {
        .callback = dmi_disable_osi_win8,
-       .ident = "Dell Inspiron 15R SE",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
        .ident = "ThinkPad Edge E530",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -322,56 +314,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
                     DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"),
                },
        },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP ProBook 2013 models",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "),
-                    DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP EliteBook 2013 models",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "),
-                    DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP ZBook 14",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP ZBook 15",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP ZBook 17",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP EliteBook 8780w",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
-               },
-       },
 
        /*
         * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
index 11c11f6b8fa1453a4a28c3931f0cf8618750fecc..714e957a871a8034ed18be2104b8c107d0b4ced9 100644 (file)
@@ -80,6 +80,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event);
 
 #ifdef CONFIG_PM_SLEEP
 static int acpi_button_resume(struct device *dev);
+#else
+#define acpi_button_resume NULL
 #endif
 static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume);
 
index e9b3081c4fe994bdfd7dcba5b54ae0533cf8f110..5bfd769fc91fa5bfd0890a146a4eed13ac342ff0 100644 (file)
@@ -713,13 +713,11 @@ static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
 static ssize_t show_docked(struct device *dev,
                           struct device_attribute *attr, char *buf)
 {
-       struct acpi_device *tmp;
-
        struct dock_station *dock_station = dev->platform_data;
+       struct acpi_device *adev = NULL;
 
-       if (!acpi_bus_get_device(dock_station->handle, &tmp))
-               return snprintf(buf, PAGE_SIZE, "1\n");
-       return snprintf(buf, PAGE_SIZE, "0\n");
+       acpi_bus_get_device(dock_station->handle, &adev);
+       return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev));
 }
 static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
 
index 959d41acc108a847308773f754fdb4fff3b1fd26..d7d32c28829b17834507bf8683f2c2a5c77d0a0d 100644 (file)
@@ -67,6 +67,8 @@ enum ec_command {
 #define ACPI_EC_DELAY          500     /* Wait 500ms max. during EC ops */
 #define ACPI_EC_UDELAY_GLK     1000    /* Wait 1ms max. to get global lock */
 #define ACPI_EC_MSI_UDELAY     550     /* Wait 550us for MSI EC */
+#define ACPI_EC_CLEAR_MAX      100     /* Maximum number of events to query
+                                        * when trying to clear the EC */
 
 enum {
        EC_FLAGS_QUERY_PENDING,         /* Query is pending */
@@ -116,6 +118,7 @@ EXPORT_SYMBOL(first_ec);
 static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
 static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
 static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
+static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 
 /* --------------------------------------------------------------------------
                              Transaction Management
@@ -440,6 +443,29 @@ acpi_handle ec_get_handle(void)
 
 EXPORT_SYMBOL(ec_get_handle);
 
+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data);
+
+/*
+ * Clears stale _Q events that might have accumulated in the EC.
+ * Run with locked ec mutex.
+ */
+static void acpi_ec_clear(struct acpi_ec *ec)
+{
+       int i, status;
+       u8 value = 0;
+
+       for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
+               status = acpi_ec_query_unlocked(ec, &value);
+               if (status || !value)
+                       break;
+       }
+
+       if (unlikely(i == ACPI_EC_CLEAR_MAX))
+               pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
+       else
+               pr_info("%d stale EC events cleared\n", i);
+}
+
 void acpi_ec_block_transactions(void)
 {
        struct acpi_ec *ec = first_ec;
@@ -463,6 +489,10 @@ void acpi_ec_unblock_transactions(void)
        mutex_lock(&ec->mutex);
        /* Allow transactions to be carried out again */
        clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
+
+       if (EC_FLAGS_CLEAR_ON_RESUME)
+               acpi_ec_clear(ec);
+
        mutex_unlock(&ec->mutex);
 }
 
@@ -821,6 +851,13 @@ static int acpi_ec_add(struct acpi_device *device)
 
        /* EC is fully operational, allow queries */
        clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+
+       /* Clear stale _Q events if hardware might require that */
+       if (EC_FLAGS_CLEAR_ON_RESUME) {
+               mutex_lock(&ec->mutex);
+               acpi_ec_clear(ec);
+               mutex_unlock(&ec->mutex);
+       }
        return ret;
 }
 
@@ -922,6 +959,30 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
        return 0;
 }
 
+/*
+ * On some hardware it is necessary to clear events accumulated by the EC during
+ * sleep. These ECs stop reporting GPEs until they are manually polled, if too
+ * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=44161
+ *
+ * Ideally, the EC should also be instructed NOT to accumulate events during
+ * sleep (which Windows seems to do somehow), but the interface to control this
+ * behaviour is not known at this time.
+ *
+ * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
+ * however it is very likely that other Samsung models are affected.
+ *
+ * On systems which don't accumulate _Q events during sleep, this extra check
+ * should be harmless.
+ */
+static int ec_clear_on_resume(const struct dmi_system_id *id)
+{
+       pr_debug("Detected system needing EC poll on resume.\n");
+       EC_FLAGS_CLEAR_ON_RESUME = 1;
+       return 0;
+}
+
 static struct dmi_system_id ec_dmi_table[] __initdata = {
        {
        ec_skip_dsdt_scan, "Compal JFL92", {
@@ -965,6 +1026,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
        ec_validate_ecdt, "ASUS hardware", {
        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
        DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
+       {
+       ec_clear_on_resume, "Samsung hardware", {
+       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
        {},
 };
 
index 1fb62900f32a9c57d329fd3e5480bc0dc7c305b8..09e423f3d8ad30fbd16d2d2b2e2766e69e64de82 100644 (file)
@@ -55,6 +55,9 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids);
 #ifdef CONFIG_PM_SLEEP
 static int acpi_fan_suspend(struct device *dev);
 static int acpi_fan_resume(struct device *dev);
+#else
+#define acpi_fan_suspend NULL
+#define acpi_fan_resume NULL
 #endif
 static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume);
 
index 52d45ea2bc4f63efcfb7e8912b087b1a568d49cc..361b40c10c3f522e28e2b334dd5f8976109bc772 100644 (file)
@@ -430,6 +430,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                                 pin_name(pin));
                }
 
+               kfree(entry);
                return 0;
        }
 
index 28baa05b8018dd6c6e6e1db93c1a5ceed74d4d74..84243c32e29c515381634b6e7b2cc6f4d219635b 100644 (file)
@@ -56,6 +56,12 @@ struct throttling_tstate {
        int target_state;               /* target T-state */
 };
 
+struct acpi_processor_throttling_arg {
+       struct acpi_processor *pr;
+       int target_state;
+       bool force;
+};
+
 #define THROTTLING_PRECHANGE       (1)
 #define THROTTLING_POSTCHANGE      (2)
 
@@ -1060,16 +1066,24 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
        return 0;
 }
 
+static long acpi_processor_throttling_fn(void *data)
+{
+       struct acpi_processor_throttling_arg *arg = data;
+       struct acpi_processor *pr = arg->pr;
+
+       return pr->throttling.acpi_processor_set_throttling(pr,
+                       arg->target_state, arg->force);
+}
+
 int acpi_processor_set_throttling(struct acpi_processor *pr,
                                                int state, bool force)
 {
-       cpumask_var_t saved_mask;
        int ret = 0;
        unsigned int i;
        struct acpi_processor *match_pr;
        struct acpi_processor_throttling *p_throttling;
+       struct acpi_processor_throttling_arg arg;
        struct throttling_tstate t_state;
-       cpumask_var_t online_throttling_cpus;
 
        if (!pr)
                return -EINVAL;
@@ -1080,14 +1094,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
        if ((state < 0) || (state > (pr->throttling.state_count - 1)))
                return -EINVAL;
 
-       if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL))
-               return -ENOMEM;
-
-       if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) {
-               free_cpumask_var(saved_mask);
-               return -ENOMEM;
-       }
-
        if (cpu_is_offline(pr->id)) {
                /*
                 * the cpu pointed by pr->id is offline. Unnecessary to change
@@ -1096,17 +1102,15 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
                return -ENODEV;
        }
 
-       cpumask_copy(saved_mask, &current->cpus_allowed);
        t_state.target_state = state;
        p_throttling = &(pr->throttling);
-       cpumask_and(online_throttling_cpus, cpu_online_mask,
-                   p_throttling->shared_cpu_map);
+
        /*
         * The throttling notifier will be called for every
         * affected cpu in order to get one proper T-state.
         * The notifier event is THROTTLING_PRECHANGE.
         */
-       for_each_cpu(i, online_throttling_cpus) {
+       for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
                t_state.cpu = i;
                acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
                                                        &t_state);
@@ -1118,21 +1122,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
         * it can be called only for the cpu pointed by pr.
         */
        if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
-               /* FIXME: use work_on_cpu() */
-               if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
-                       /* Can't migrate to the pr->id CPU. Exit */
-                       ret = -ENODEV;
-                       goto exit;
-               }
-               ret = p_throttling->acpi_processor_set_throttling(pr,
-                                               t_state.target_state, force);
+               arg.pr = pr;
+               arg.target_state = state;
+               arg.force = force;
+               ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg);
        } else {
                /*
                 * When the T-state coordination is SW_ALL or HW_ALL,
                 * it is necessary to set T-state for every affected
                 * cpus.
                 */
-               for_each_cpu(i, online_throttling_cpus) {
+               for_each_cpu_and(i, cpu_online_mask,
+                   p_throttling->shared_cpu_map) {
                        match_pr = per_cpu(processors, i);
                        /*
                         * If the pointer is invalid, we will report the
@@ -1153,13 +1154,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
                                        "on CPU %d\n", i));
                                continue;
                        }
-                       t_state.cpu = i;
-                       /* FIXME: use work_on_cpu() */
-                       if (set_cpus_allowed_ptr(current, cpumask_of(i)))
-                               continue;
-                       ret = match_pr->throttling.
-                               acpi_processor_set_throttling(
-                               match_pr, t_state.target_state, force);
+
+                       arg.pr = match_pr;
+                       arg.target_state = state;
+                       arg.force = force;
+                       ret = work_on_cpu(pr->id, acpi_processor_throttling_fn,
+                               &arg);
                }
        }
        /*
@@ -1168,17 +1168,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
         * affected cpu to update the T-states.
         * The notifier event is THROTTLING_POSTCHANGE
         */
-       for_each_cpu(i, online_throttling_cpus) {
+       for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
                t_state.cpu = i;
                acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
                                                        &t_state);
        }
-       /* restore the previous state */
-       /* FIXME: use work_on_cpu() */
-       set_cpus_allowed_ptr(current, saved_mask);
-exit:
-       free_cpumask_var(online_throttling_cpus);
-       free_cpumask_var(saved_mask);
+
        return ret;
 }
 
index b7201fc6f1e19c06c798889900c1e9c689494c8d..0bdacc5e26a3b9411b82a5fe4772c2c9f9b7d490 100644 (file)
@@ -77,18 +77,24 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
        switch (ares->type) {
        case ACPI_RESOURCE_TYPE_MEMORY24:
                memory24 = &ares->data.memory24;
+               if (!memory24->address_length)
+                       return false;
                acpi_dev_get_memresource(res, memory24->minimum,
                                         memory24->address_length,
                                         memory24->write_protect);
                break;
        case ACPI_RESOURCE_TYPE_MEMORY32:
                memory32 = &ares->data.memory32;
+               if (!memory32->address_length)
+                       return false;
                acpi_dev_get_memresource(res, memory32->minimum,
                                         memory32->address_length,
                                         memory32->write_protect);
                break;
        case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
                fixed_memory32 = &ares->data.fixed_memory32;
+               if (!fixed_memory32->address_length)
+                       return false;
                acpi_dev_get_memresource(res, fixed_memory32->address,
                                         fixed_memory32->address_length,
                                         fixed_memory32->write_protect);
@@ -144,12 +150,16 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
        switch (ares->type) {
        case ACPI_RESOURCE_TYPE_IO:
                io = &ares->data.io;
+               if (!io->address_length)
+                       return false;
                acpi_dev_get_ioresource(res, io->minimum,
                                        io->address_length,
                                        io->io_decode);
                break;
        case ACPI_RESOURCE_TYPE_FIXED_IO:
                fixed_io = &ares->data.fixed_io;
+               if (!fixed_io->address_length)
+                       return false;
                acpi_dev_get_ioresource(res, fixed_io->address,
                                        fixed_io->address_length,
                                        ACPI_DECODE_10);
index d465ae6cdd004b9813cc333529c54ef29abcb16f..dbd48498b93863a1fa37ab0b23706f2dae89345d 100644 (file)
@@ -450,7 +450,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev,
 {
        unsigned long x;
        struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
-       if (sscanf(buf, "%ld\n", &x) == 1)
+       if (sscanf(buf, "%lu\n", &x) == 1)
                battery->alarm_capacity = x /
                        (1000 * acpi_battery_scale(battery));
        if (battery->present)
@@ -668,6 +668,8 @@ static int acpi_sbs_resume(struct device *dev)
        acpi_sbs_callback(sbs);
        return 0;
 }
+#else
+#define acpi_sbs_resume NULL
 #endif
 
 static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume);
index b718806657cdac29d9ccb3a1cad3fe6528865176..c40fb2e81bbc5d4ce9266174c0c2d7614755c644 100644 (file)
@@ -71,6 +71,17 @@ static int acpi_sleep_prepare(u32 acpi_state)
        return 0;
 }
 
+static bool acpi_sleep_state_supported(u8 sleep_state)
+{
+       acpi_status status;
+       u8 type_a, type_b;
+
+       status = acpi_get_sleep_type_data(sleep_state, &type_a, &type_b);
+       return ACPI_SUCCESS(status) && (!acpi_gbl_reduced_hardware
+               || (acpi_gbl_FADT.sleep_control.address
+                       && acpi_gbl_FADT.sleep_status.address));
+}
+
 #ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
 
@@ -604,15 +615,9 @@ static void acpi_sleep_suspend_setup(void)
 {
        int i;
 
-       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
-               acpi_status status;
-               u8 type_a, type_b;
-
-               status = acpi_get_sleep_type_data(i, &type_a, &type_b);
-               if (ACPI_SUCCESS(status)) {
+       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++)
+               if (acpi_sleep_state_supported(i))
                        sleep_states[i] = 1;
-               }
-       }
 
        suspend_set_ops(old_suspend_ordering ?
                &acpi_suspend_ops_old : &acpi_suspend_ops);
@@ -740,11 +745,7 @@ static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
 
 static void acpi_sleep_hibernate_setup(void)
 {
-       acpi_status status;
-       u8 type_a, type_b;
-
-       status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
-       if (ACPI_FAILURE(status))
+       if (!acpi_sleep_state_supported(ACPI_STATE_S4))
                return;
 
        hibernation_set_ops(old_suspend_ordering ?
@@ -793,8 +794,6 @@ static void acpi_power_off(void)
 
 int __init acpi_sleep_init(void)
 {
-       acpi_status status;
-       u8 type_a, type_b;
        char supported[ACPI_S_STATE_COUNT * 3 + 1];
        char *pos = supported;
        int i;
@@ -806,8 +805,7 @@ int __init acpi_sleep_init(void)
        acpi_sleep_suspend_setup();
        acpi_sleep_hibernate_setup();
 
-       status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
                sleep_states[ACPI_STATE_S5] = 1;
                pm_power_off_prepare = acpi_power_off_prepare;
                pm_power_off = acpi_power_off;
index 8349a555b92b8aa6d6584f9c2c5c9ccf7a27737f..08626c851be7eef72c5a639522b708586736adc5 100644 (file)
@@ -102,6 +102,8 @@ MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
 
 #ifdef CONFIG_PM_SLEEP
 static int acpi_thermal_resume(struct device *dev);
+#else
+#define acpi_thermal_resume NULL
 #endif
 static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
 
index b727d105046d234ae8ef2a5669e53e61b82e7123..b6ba88ed31aeeb1854e48bb73b95fc59a4d58706 100644 (file)
@@ -81,11 +81,12 @@ static bool allow_duplicates;
 module_param(allow_duplicates, bool, 0644);
 
 /*
- * For Windows 8 systems: if set ture and the GPU driver has
- * registered a backlight interface, skip registering ACPI video's.
+ * For Windows 8 systems: used to decide if video module
+ * should skip registering backlight interface of its own.
  */
-static bool use_native_backlight = false;
-module_param(use_native_backlight, bool, 0644);
+static int use_native_backlight_param = -1;
+module_param_named(use_native_backlight, use_native_backlight_param, int, 0444);
+static bool use_native_backlight_dmi = false;
 
 static int register_count;
 static struct mutex video_list_lock;
@@ -231,9 +232,17 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
 static int acpi_video_switch_brightness(struct acpi_video_device *device,
                                         int event);
 
+static bool acpi_video_use_native_backlight(void)
+{
+       if (use_native_backlight_param != -1)
+               return use_native_backlight_param;
+       else
+               return use_native_backlight_dmi;
+}
+
 static bool acpi_video_verify_backlight_support(void)
 {
-       if (acpi_osi_is_win8() && use_native_backlight &&
+       if (acpi_osi_is_win8() && acpi_video_use_native_backlight() &&
            backlight_device_registered(BACKLIGHT_RAW))
                return false;
        return acpi_video_backlight_support();
@@ -398,6 +407,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d)
        return 0;
 }
 
+static int __init video_set_use_native_backlight(const struct dmi_system_id *d)
+{
+       use_native_backlight_dmi = true;
+       return 0;
+}
+
 static struct dmi_system_id video_dmi_table[] __initdata = {
        /*
         * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
@@ -442,6 +457,120 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"),
                },
        },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "ThinkPad T430s",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "ThinkPad X230",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "ThinkPad X1 Carbon",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "Lenovo Yoga 13",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "Dell Inspiron 7520",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "Inspiron 7520"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "Acer Aspire 5733Z",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5733Z"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "Acer Aspire V5-431",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ProBook 4340s",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "HP ProBook 4340s"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ProBook 2013 models",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "),
+               DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP EliteBook 2013 models",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "),
+               DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ZBook 14",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ZBook 15",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ZBook 17",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP EliteBook 8780w",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
+               },
+       },
        {}
 };
 
@@ -685,6 +814,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
        union acpi_object *o;
        struct acpi_video_device_brightness *br = NULL;
        int result = -EINVAL;
+       u32 value;
 
        if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
@@ -715,7 +845,12 @@ acpi_video_init_brightness(struct acpi_video_device *device)
                        printk(KERN_ERR PREFIX "Invalid data\n");
                        continue;
                }
-               br->levels[count] = (u32) o->integer.value;
+               value = (u32) o->integer.value;
+               /* Skip duplicate entries */
+               if (count > 2 && br->levels[count - 1] == value)
+                       continue;
+
+               br->levels[count] = value;
 
                if (br->levels[count] > max_level)
                        max_level = br->levels[count];
index a697b77b8865a163cd23fe591db0242631ca742f..19080c8e2f2a9c6d5df7f5475d581f5348ed9e8e 100644 (file)
@@ -168,22 +168,6 @@ static struct dmi_system_id video_detect_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
                },
        },
-       {
-       .callback = video_detect_force_vendor,
-       .ident = "HP EliteBook Revolve 810",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook Revolve 810 G1"),
-               },
-       },
-       {
-       .callback = video_detect_force_vendor,
-       .ident = "Lenovo Yoga 13",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"),
-               },
-       },
        { },
 };
 
index 4e737728aee207a5d644d6fa0d39b0e3c402bd47..868429a47be41a2c50ff146389df25dfcb8f5b30 100644 (file)
@@ -247,6 +247,7 @@ config SATA_HIGHBANK
 
 config SATA_MV
        tristate "Marvell SATA support"
+       select GENERIC_PHY
        help
          This option enables support for the Marvell Serial ATA family.
          Currently supports 88SX[56]0[48][01] PCI(-X) chips,
index dc2756fb6f3369b95cdb015fb8b32f97ff64d887..c81d809c111b238e72f65d185add59f5bef4fade 100644 (file)
@@ -61,6 +61,7 @@ enum board_ids {
        /* board IDs by feature in alphabetical order */
        board_ahci,
        board_ahci_ign_iferr,
+       board_ahci_noncq,
        board_ahci_nosntf,
        board_ahci_yes_fbs,
 
@@ -121,6 +122,13 @@ static const struct ata_port_info ahci_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
+       [board_ahci_noncq] = {
+               AHCI_HFLAGS     (AHCI_HFLAG_NO_NCQ),
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_ops,
+       },
        [board_ahci_nosntf] = {
                AHCI_HFLAGS     (AHCI_HFLAG_NO_SNTF),
                .flags          = AHCI_FLAG_COMMON,
@@ -452,6 +460,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci },   /* ASM1061 */
        { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },   /* ASM1062 */
 
+       /*
+        * Samsung SSDs found on some macbooks.  NCQ times out.
+        * https://bugzilla.kernel.org/show_bug.cgi?id=60731
+        */
+       { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq },
+
        /* Enmotus */
        { PCI_DEVICE(0x1c44, 0x8000), board_ahci },
 
@@ -1170,8 +1184,10 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
 
        nvec = rc;
        rc = pci_enable_msi_block(pdev, nvec);
-       if (rc)
+       if (rc < 0)
                goto intx;
+       else if (rc > 0)
+               goto single_msi;
 
        return nvec;
 
index 1a3dbd1b196ecb121b1ee9d34388ecd00c307b71..8cb2522d592ac87f7b144f1f41d244cd5df777dc 100644 (file)
@@ -4175,6 +4175,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 
        /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
        { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
+       { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA },
 
        /* Blacklist entries taken from Silicon Image 3124/3132
           Windows driver .inf file - also several Linux problem reports */
@@ -4224,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 
        /* devices that don't properly handle queued TRIM commands */
        { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
-       { "Crucial_CT???M500SSD1",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
+       { "Crucial_CT???M500SSD*",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
 
        /*
         * Some WD SATA-I drives spin up and down erratically when the link
index 20fd337a57314a2928c9208bf706ffabed0c4dd5..7ccc084bf1dfb8f7b979f5e7ae777e030303d1b8 100644 (file)
@@ -447,8 +447,11 @@ static void sata_pmp_quirks(struct ata_port *ap)
                 * otherwise.  Don't try hard to recover it.
                 */
                ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
-       } else if (vendor == 0x197b && devid == 0x2352) {
-               /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */
+       } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) {
+               /*
+                * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350?
+                * 0x0325: jmicron JMB394.
+                */
                ata_for_each_link(link, ap, EDGE) {
                        /* SRST breaks detection and disks get misclassified
                         * LPM disabled to avoid potential problems
index 26386f0b89a8f4583c397ca9da154a9c499c6d2f..b0b18ec5465ffe32bae62d11f97d1b0cba8c313c 100644 (file)
@@ -119,7 +119,9 @@ static int pata_imx_probe(struct platform_device *pdev)
                return PTR_ERR(priv->clk);
        }
 
-       clk_prepare_enable(priv->clk);
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               return ret;
 
        host = ata_host_alloc(&pdev->dev, 1);
        if (!host) {
@@ -212,7 +214,9 @@ static int pata_imx_resume(struct device *dev)
        struct ata_host *host = dev_get_drvdata(dev);
        struct pata_imx_priv *priv = host->private_data;
 
-       clk_prepare_enable(priv->clk);
+       int ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               return ret;
 
        __raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL);
 
index 52b8181ddafd98cbfb550b3f082062280feec6d2..05c8a44adf8edea590ec983a7f843c1f5b6b1b55 100644 (file)
@@ -4104,7 +4104,6 @@ static int mv_platform_probe(struct platform_device *pdev)
        if (!hpriv->port_phys)
                return -ENOMEM;
        host->private_data = hpriv;
-       hpriv->n_ports = n_ports;
        hpriv->board_idx = chip_soc;
 
        host->iomap = NULL;
@@ -4132,13 +4131,18 @@ static int mv_platform_probe(struct platform_device *pdev)
                        rc = PTR_ERR(hpriv->port_phys[port]);
                        hpriv->port_phys[port] = NULL;
                        if (rc != -EPROBE_DEFER)
-                               dev_warn(&pdev->dev, "error getting phy %d",
-                                       rc);
+                               dev_warn(&pdev->dev, "error getting phy %d", rc);
+
+                       /* Cleanup only the initialized ports */
+                       hpriv->n_ports = port;
                        goto err;
                } else
                        phy_power_on(hpriv->port_phys[port]);
        }
 
+       /* All the ports have been initialized */
+       hpriv->n_ports = n_ports;
+
        /*
         * (Re-)program MBUS remapping windows if we are asked to.
         */
@@ -4176,7 +4180,7 @@ err:
                clk_disable_unprepare(hpriv->clk);
                clk_put(hpriv->clk);
        }
-       for (port = 0; port < n_ports; port++) {
+       for (port = 0; port < hpriv->n_ports; port++) {
                if (!IS_ERR(hpriv->port_clks[port])) {
                        clk_disable_unprepare(hpriv->port_clks[port]);
                        clk_put(hpriv->port_clks[port]);
index d67fc351343ca841f7ea95b68e401f52f58953c2..b7695e804635b87c0d7c787be1d900facaa68963 100644 (file)
@@ -157,6 +157,7 @@ static const struct sil_drivelist {
        { "ST380011ASL",        SIL_QUIRK_MOD15WRITE },
        { "ST3120022ASL",       SIL_QUIRK_MOD15WRITE },
        { "ST3160021ASL",       SIL_QUIRK_MOD15WRITE },
+       { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE },
        { "Maxtor 4D060H3",     SIL_QUIRK_UDMA5MAX },
        { }
 };
index 8a97ddfa61222db79506dcecebc619ab5a333865..c30df50e4440c3af5639af58dd567c37e8bf40e6 100644 (file)
@@ -1580,6 +1580,7 @@ static int fw_pm_notify(struct notifier_block *notify_block,
        switch (mode) {
        case PM_HIBERNATION_PREPARE:
        case PM_SUSPEND_PREPARE:
+       case PM_RESTORE_PREPARE:
                kill_requests_without_uevent();
                device_cache_fw_images();
                break;
index 8184451b57c04999bd23c286080e14ca7f069031..422b7d84f686b90147f97565210687d343a3d9eb 100644 (file)
@@ -874,7 +874,7 @@ bio_pageinc(struct bio *bio)
                /* Non-zero page count for non-head members of
                 * compound pages is no longer allowed by the kernel.
                 */
-               page = compound_trans_head(bv.bv_page);
+               page = compound_head(bv.bv_page);
                atomic_inc(&page->_count);
        }
 }
@@ -887,7 +887,7 @@ bio_pagedec(struct bio *bio)
        struct bvec_iter iter;
 
        bio_for_each_segment(bv, bio, iter) {
-               page = compound_trans_head(bv.bv_page);
+               page = compound_head(bv.bv_page);
                atomic_dec(&page->_count);
        }
 }
index b52e9a6d6aad6d602bf3a9d6f73c9b4c277c7e17..54174cb32febe10a45eddd8e837d8267bfe594a1 100644 (file)
@@ -53,7 +53,7 @@
 #define MTIP_FTL_REBUILD_TIMEOUT_MS    2400000
 
 /* unaligned IO handling */
-#define MTIP_MAX_UNALIGNED_SLOTS       8
+#define MTIP_MAX_UNALIGNED_SLOTS       2
 
 /* Macro to extract the tag bit number from a tag value. */
 #define MTIP_TAG_BIT(tag)      (tag & 0x1F)
index 011e55d820b1811a3379a65a4ef754fcc785f3ef..51c557cfd92b37cf6b7aecdfa50d212fdacc05ee 100644 (file)
@@ -612,6 +612,8 @@ static ssize_t disksize_store(struct device *dev,
 
        disksize = PAGE_ALIGN(disksize);
        meta = zram_meta_alloc(disksize);
+       if (!meta)
+               return -ENOMEM;
        down_write(&zram->init_lock);
        if (zram->init_done) {
                up_write(&zram->init_lock);
index 106d1d8e16ad4f87ac510f5d02b53dc36e8f23ef..4f78a9d39dc8fe960e194b1dc3e8b0bf703733e3 100644 (file)
@@ -62,50 +62,53 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0CF3, 0x3000) },
 
        /* Atheros AR3011 with sflash firmware*/
+       { USB_DEVICE(0x0489, 0xE027) },
+       { USB_DEVICE(0x0489, 0xE03D) },
+       { USB_DEVICE(0x0930, 0x0215) },
        { USB_DEVICE(0x0CF3, 0x3002) },
        { USB_DEVICE(0x0CF3, 0xE019) },
        { USB_DEVICE(0x13d3, 0x3304) },
-       { USB_DEVICE(0x0930, 0x0215) },
-       { USB_DEVICE(0x0489, 0xE03D) },
-       { USB_DEVICE(0x0489, 0xE027) },
 
        /* Atheros AR9285 Malbec with sflash firmware */
        { USB_DEVICE(0x03F0, 0x311D) },
 
        /* Atheros AR3012 with sflash firmware*/
-       { USB_DEVICE(0x0CF3, 0x0036) },
-       { USB_DEVICE(0x0CF3, 0x3004) },
-       { USB_DEVICE(0x0CF3, 0x3008) },
-       { USB_DEVICE(0x0CF3, 0x311D) },
-       { USB_DEVICE(0x0CF3, 0x817a) },
-       { USB_DEVICE(0x13d3, 0x3375) },
+       { USB_DEVICE(0x0489, 0xe04d) },
+       { USB_DEVICE(0x0489, 0xe04e) },
+       { USB_DEVICE(0x0489, 0xe057) },
+       { USB_DEVICE(0x0489, 0xe056) },
+       { USB_DEVICE(0x0489, 0xe05f) },
+       { USB_DEVICE(0x04c5, 0x1330) },
        { USB_DEVICE(0x04CA, 0x3004) },
        { USB_DEVICE(0x04CA, 0x3005) },
        { USB_DEVICE(0x04CA, 0x3006) },
        { USB_DEVICE(0x04CA, 0x3008) },
        { USB_DEVICE(0x04CA, 0x300b) },
-       { USB_DEVICE(0x13d3, 0x3362) },
-       { USB_DEVICE(0x0CF3, 0xE004) },
-       { USB_DEVICE(0x0CF3, 0xE005) },
        { USB_DEVICE(0x0930, 0x0219) },
        { USB_DEVICE(0x0930, 0x0220) },
-       { USB_DEVICE(0x0489, 0xe057) },
-       { USB_DEVICE(0x13d3, 0x3393) },
-       { USB_DEVICE(0x0489, 0xe04e) },
-       { USB_DEVICE(0x0489, 0xe056) },
-       { USB_DEVICE(0x0489, 0xe04d) },
-       { USB_DEVICE(0x04c5, 0x1330) },
-       { USB_DEVICE(0x13d3, 0x3402) },
+       { USB_DEVICE(0x0b05, 0x17d0) },
+       { USB_DEVICE(0x0CF3, 0x0036) },
+       { USB_DEVICE(0x0CF3, 0x3004) },
+       { USB_DEVICE(0x0CF3, 0x3008) },
+       { USB_DEVICE(0x0CF3, 0x311D) },
+       { USB_DEVICE(0x0CF3, 0x311E) },
+       { USB_DEVICE(0x0CF3, 0x311F) },
        { USB_DEVICE(0x0cf3, 0x3121) },
+       { USB_DEVICE(0x0CF3, 0x817a) },
        { USB_DEVICE(0x0cf3, 0xe003) },
-       { USB_DEVICE(0x0489, 0xe05f) },
+       { USB_DEVICE(0x0CF3, 0xE004) },
+       { USB_DEVICE(0x0CF3, 0xE005) },
+       { USB_DEVICE(0x13d3, 0x3362) },
+       { USB_DEVICE(0x13d3, 0x3375) },
+       { USB_DEVICE(0x13d3, 0x3393) },
+       { USB_DEVICE(0x13d3, 0x3402) },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE02C) },
 
        /* Atheros AR5BBU22 with sflash firmware */
-       { USB_DEVICE(0x0489, 0xE03C) },
        { USB_DEVICE(0x0489, 0xE036) },
+       { USB_DEVICE(0x0489, 0xE03C) },
 
        { }     /* Terminating entry */
 };
@@ -118,36 +121,39 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
 static const struct usb_device_id ath3k_blist_tbl[] = {
 
        /* Atheros AR3012 with sflash firmware*/
-       { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU22 with sflash firmware */
-       { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
 
        { }     /* Terminating entry */
 };
index baeaaed299e4e339ee455833c94c9d7aa24421c4..199b9d42489c834c0f244bf506961a352fed7a04 100644 (file)
@@ -101,21 +101,24 @@ static const struct usb_device_id btusb_table[] = {
        { USB_DEVICE(0x0c10, 0x0000) },
 
        /* Broadcom BCM20702A0 */
+       { USB_DEVICE(0x0489, 0xe042) },
+       { USB_DEVICE(0x04ca, 0x2003) },
        { USB_DEVICE(0x0b05, 0x17b5) },
        { USB_DEVICE(0x0b05, 0x17cb) },
-       { USB_DEVICE(0x04ca, 0x2003) },
-       { USB_DEVICE(0x0489, 0xe042) },
        { USB_DEVICE(0x413c, 0x8197) },
 
        /* Foxconn - Hon Hai */
        { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
 
-       /*Broadcom devices with vendor specific id */
+       /* Broadcom devices with vendor specific id */
        { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
 
        /* Belkin F8065bf - Broadcom based */
        { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
 
+       /* IMC Networks - Broadcom based */
+       { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) },
+
        { }     /* Terminating entry */
 };
 
@@ -129,55 +132,58 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
 
        /* Atheros 3011 with sflash firmware */
+       { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
+       { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
+       { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
        { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
        { USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE },
        { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
-       { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
-       { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
-       { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
 
        /* Atheros AR9285 Malbec with sflash firmware */
        { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
 
        /* Atheros 3012 with sflash firmware */
-       { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
 
        /* Atheros AR5BBU12 with sflash firmware */
-       { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
 
        /* Broadcom BCM2035 */
-       { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
-       { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
        { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
+       { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
 
        /* Broadcom BCM2045 */
        { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },
index 1ef6990a5c7e7c0387b4d9b6aafcb7a5c6f5cdc2..add1c6a720637a4009e35bb2b0a9b4e605fb59b8 100644 (file)
@@ -359,7 +359,7 @@ static const struct file_operations vhci_fops = {
 static struct miscdevice vhci_miscdev= {
        .name   = "vhci",
        .fops   = &vhci_fops,
-       .minor  = MISC_DYNAMIC_MINOR,
+       .minor  = VHCI_MINOR,
 };
 
 static int __init vhci_init(void)
@@ -385,3 +385,4 @@ MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("devname:vhci");
+MODULE_ALIAS_MISCDEV(VHCI_MINOR);
index bd313f7816a8d9461deba6889b99415b87010467..c1af80bcdf2082c8d0d7b32e28eb9122c59ac53f 100644 (file)
@@ -242,7 +242,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
 
        irq = irq_of_parse_and_map(np, 0);
        if (!irq)
-               return;
+               goto out_free_characteristics;
 
        clk = at91_clk_register_master(pmc, irq, name, num_parents,
                                       parent_names, layout,
index 6a934a5296bd4ca2867146dc06272ea1003e238e..05e04ce0f1488f7301ad5153f687860bf872f8bc 100644 (file)
@@ -494,6 +494,9 @@ static const struct file_operations nomadik_src_clk_debugfs_ops = {
 
 static int __init nomadik_src_clk_init_debugfs(void)
 {
+       /* Vital for multiplatform */
+       if (!src_base)
+               return -ENODEV;
        src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
        src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
        debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
index 5517944495d893cc3c8dd60569b58e67e9289765..c42e608af6bbe0980717a74e69a143cdc742f1b1 100644 (file)
@@ -2226,24 +2226,25 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
  */
 int __clk_get(struct clk *clk)
 {
-       if (clk && !try_module_get(clk->owner))
-               return 0;
+       if (clk) {
+               if (!try_module_get(clk->owner))
+                       return 0;
 
-       kref_get(&clk->ref);
+               kref_get(&clk->ref);
+       }
        return 1;
 }
 
 void __clk_put(struct clk *clk)
 {
-       if (WARN_ON_ONCE(IS_ERR(clk)))
+       if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
                return;
 
        clk_prepare_lock();
        kref_put(&clk->ref, __clk_release);
        clk_prepare_unlock();
 
-       if (clk)
-               module_put(clk->owner);
+       module_put(clk->owner);
 }
 
 /***        clk rate change notifiers        ***/
index 17a598398a53df461e110ca5c16d29e7bc92e6f5..86f1e362eafb8e29c02fae393620d39d32278529 100644 (file)
@@ -179,6 +179,7 @@ static struct clk *clk_register_psc(struct device *dev,
 
        init.name = name;
        init.ops = &clk_psc_ops;
+       init.flags = 0;
        init.parent_names = (parent_name ? &parent_name : NULL);
        init.num_parents = (parent_name ? 1 : 0);
 
index 81a202d12a7ad89ab56909fce6782baa7fb94ec2..bef198a83863aaa79e21ca1c4e1401238cae31b7 100644 (file)
@@ -141,13 +141,6 @@ static const struct coreclk_soc_desc a370_coreclks = {
        .num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
 };
 
-static void __init a370_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &a370_coreclks);
-}
-CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock",
-              a370_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -168,9 +161,15 @@ static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = {
        { }
 };
 
-static void __init a370_clk_gating_init(struct device_node *np)
+static void __init a370_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, a370_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock");
+
+       mvebu_coreclk_setup(np, &a370_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, a370_gating_desc);
 }
-CLK_OF_DECLARE(a370_clk_gating, "marvell,armada-370-gating-clock",
-              a370_clk_gating_init);
+CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init);
+
index 9922c4475aa8b3f7d01c2881c8a757b94f9027af..b3094315a3c0faa89926dcf7442d5034f39b4f15 100644 (file)
@@ -158,13 +158,6 @@ static const struct coreclk_soc_desc axp_coreclks = {
        .num_ratios = ARRAY_SIZE(axp_coreclk_ratios),
 };
 
-static void __init axp_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &axp_coreclks);
-}
-CLK_OF_DECLARE(axp_core_clk, "marvell,armada-xp-core-clock",
-              axp_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -202,9 +195,14 @@ static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = {
        { }
 };
 
-static void __init axp_clk_gating_init(struct device_node *np)
+static void __init axp_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, axp_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,armada-xp-gating-clock");
+
+       mvebu_coreclk_setup(np, &axp_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, axp_gating_desc);
 }
-CLK_OF_DECLARE(axp_clk_gating, "marvell,armada-xp-gating-clock",
-              axp_clk_gating_init);
+CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init);
index 38aee1e3f242b237079aaeb775aa2fd8dae89453..b8c2424ac9261dea5c36553b09f5262bba359299 100644 (file)
@@ -154,12 +154,6 @@ static const struct coreclk_soc_desc dove_coreclks = {
        .num_ratios = ARRAY_SIZE(dove_coreclk_ratios),
 };
 
-static void __init dove_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &dove_coreclks);
-}
-CLK_OF_DECLARE(dove_core_clk, "marvell,dove-core-clock", dove_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -186,9 +180,14 @@ static const struct clk_gating_soc_desc dove_gating_desc[] __initconst = {
        { }
 };
 
-static void __init dove_clk_gating_init(struct device_node *np)
+static void __init dove_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, dove_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock");
+
+       mvebu_coreclk_setup(np, &dove_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, dove_gating_desc);
 }
-CLK_OF_DECLARE(dove_clk_gating, "marvell,dove-gating-clock",
-              dove_clk_gating_init);
+CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init);
index 2636a55f29f9403df92aec0c11e5a504fc7f9deb..ddb666a86500964201db0ad6d3a3724511302b59 100644 (file)
@@ -193,13 +193,6 @@ static const struct coreclk_soc_desc kirkwood_coreclks = {
        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 };
 
-static void __init kirkwood_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &kirkwood_coreclks);
-}
-CLK_OF_DECLARE(kirkwood_core_clk, "marvell,kirkwood-core-clock",
-              kirkwood_coreclk_init);
-
 static const struct coreclk_soc_desc mv88f6180_coreclks = {
        .get_tclk_freq = kirkwood_get_tclk_freq,
        .get_cpu_freq = mv88f6180_get_cpu_freq,
@@ -208,13 +201,6 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = {
        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 };
 
-static void __init mv88f6180_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &mv88f6180_coreclks);
-}
-CLK_OF_DECLARE(mv88f6180_core_clk, "marvell,mv88f6180-core-clock",
-              mv88f6180_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -239,9 +225,21 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
        { }
 };
 
-static void __init kirkwood_clk_gating_init(struct device_node *np)
+static void __init kirkwood_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, kirkwood_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
+
+
+       if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
+               mvebu_coreclk_setup(np, &mv88f6180_coreclks);
+       else
+               mvebu_coreclk_setup(np, &kirkwood_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
 }
-CLK_OF_DECLARE(kirkwood_clk_gating, "marvell,kirkwood-gating-clock",
-              kirkwood_clk_gating_init);
+CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
+              kirkwood_clk_init);
+CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
+              kirkwood_clk_init);
index a59ec217a12437785ea1c689b28744bfcd19ac3d..99c27b1c625b8e3eaf514895a0a13ebf8b94fdef 100644 (file)
@@ -26,6 +26,8 @@ struct rcar_gen2_cpg {
        void __iomem *reg;
 };
 
+#define CPG_FRQCRB                     0x00000004
+#define CPG_FRQCRB_KICK                        BIT(31)
 #define CPG_SDCKCR                     0x00000074
 #define CPG_PLL0CR                     0x000000d8
 #define CPG_FRQCRC                     0x000000e0
@@ -45,6 +47,7 @@ struct rcar_gen2_cpg {
 struct cpg_z_clk {
        struct clk_hw hw;
        void __iomem *reg;
+       void __iomem *kick_reg;
 };
 
 #define to_z_clk(_hw)  container_of(_hw, struct cpg_z_clk, hw)
@@ -83,17 +86,45 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct cpg_z_clk *zclk = to_z_clk(hw);
        unsigned int mult;
-       u32 val;
+       u32 val, kick;
+       unsigned int i;
 
        mult = div_u64((u64)rate * 32, parent_rate);
        mult = clamp(mult, 1U, 32U);
 
+       if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
+               return -EBUSY;
+
        val = clk_readl(zclk->reg);
        val &= ~CPG_FRQCRC_ZFC_MASK;
        val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
        clk_writel(val, zclk->reg);
 
-       return 0;
+       /*
+        * Set KICK bit in FRQCRB to update hardware setting and wait for
+        * clock change completion.
+        */
+       kick = clk_readl(zclk->kick_reg);
+       kick |= CPG_FRQCRB_KICK;
+       clk_writel(kick, zclk->kick_reg);
+
+       /*
+        * Note: There is no HW information about the worst case latency.
+        *
+        * Using experimental measurements, it seems that no more than
+        * ~10 iterations are needed, independently of the CPU rate.
+        * Since this value might be dependant of external xtal rate, pll1
+        * rate or even the other emulation clocks rate, use 1000 as a
+        * "super" safe value.
+        */
+       for (i = 1000; i; i--) {
+               if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
+                       return 0;
+
+               cpu_relax();
+       }
+
+       return -ETIMEDOUT;
 }
 
 static const struct clk_ops cpg_z_clk_ops = {
@@ -120,6 +151,7 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
        init.num_parents = 1;
 
        zclk->reg = cpg->reg + CPG_FRQCRC;
+       zclk->kick_reg = cpg->reg + CPG_FRQCRB;
        zclk->hw.init = &init;
 
        clk = clk_register(NULL, &zclk->hw);
@@ -186,7 +218,7 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
                             const char *name)
 {
        const struct clk_div_table *table = NULL;
-       const char *parent_name = "main";
+       const char *parent_name;
        unsigned int shift;
        unsigned int mult = 1;
        unsigned int div = 1;
@@ -201,23 +233,31 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
                 * the multiplier value.
                 */
                u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+               parent_name = "main";
                mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
        } else if (!strcmp(name, "pll1")) {
+               parent_name = "main";
                mult = config->pll1_mult / 2;
        } else if (!strcmp(name, "pll3")) {
+               parent_name = "main";
                mult = config->pll3_mult;
        } else if (!strcmp(name, "lb")) {
+               parent_name = "pll1_div2";
                div = cpg_mode & BIT(18) ? 36 : 24;
        } else if (!strcmp(name, "qspi")) {
+               parent_name = "pll1_div2";
                div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
-                   ? 16 : 20;
+                   ? 8 : 10;
        } else if (!strcmp(name, "sdh")) {
+               parent_name = "pll1_div2";
                table = cpg_sdh_div_table;
                shift = 8;
        } else if (!strcmp(name, "sd0")) {
+               parent_name = "pll1_div2";
                table = cpg_sd01_div_table;
                shift = 4;
        } else if (!strcmp(name, "sd1")) {
+               parent_name = "pll1_div2";
                table = cpg_sd01_div_table;
                shift = 0;
        } else if (!strcmp(name, "z")) {
index 4d75b1f37e3a4b74ee4606ce33d54b8a771beb6a..290f9c1a37498ccf16ae0b09804ca15e722a2da2 100644 (file)
@@ -59,7 +59,7 @@ static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
                return 0;
 
        if (divider_ux1 > get_max_div(divider))
-               return -EINVAL;
+               return get_max_div(divider);
 
        return divider_ux1;
 }
index cf0c323f2c36ec453deed1c5374fbbce4df543b2..c39613c519af85aa5faf14cc02857219cde56a3b 100644 (file)
@@ -180,9 +180,13 @@ enum clk_id {
        tegra_clk_sbc6_8,
        tegra_clk_sclk,
        tegra_clk_sdmmc1,
+       tegra_clk_sdmmc1_8,
        tegra_clk_sdmmc2,
+       tegra_clk_sdmmc2_8,
        tegra_clk_sdmmc3,
+       tegra_clk_sdmmc3_8,
        tegra_clk_sdmmc4,
+       tegra_clk_sdmmc4_8,
        tegra_clk_se,
        tegra_clk_soc_therm,
        tegra_clk_sor0,
index 5c35885f4a7cee9a4ecb9309f93c345befe28a2e..1fa5c3f33b2033a5e4a32716706d2221d548adf1 100644 (file)
@@ -371,9 +371,7 @@ static const char *mux_pllp3_pllc_clkm[] = {
 static const char *mux_pllm_pllc_pllp_plla_pllc2_c3_clkm[] = {
        "pll_m", "pll_c", "pll_p", "pll_a", "pll_c2", "pll_c3", "clk_m"
 };
-static u32 mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx[] = {
-       [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6,
-};
+#define mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx NULL
 
 static const char *mux_pllm_pllc2_c_c3_pllp_plla_pllc4[] = {
        "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0", "pll_c4",
@@ -465,6 +463,10 @@ static struct tegra_periph_init_data periph_clks[] = {
        MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
        MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
        MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
+       MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1_8),
+       MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2_8),
+       MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3_8),
+       MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4_8),
        MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8),
        MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8),
        MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8),
@@ -492,7 +494,7 @@ static struct tegra_periph_init_data periph_clks[] = {
        UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb),
        UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc),
        UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd),
-       UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 65, tegra_clk_uarte),
+       UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte),
        XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src),
        XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
        XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
index 05dce4aa2c11e2a0d3e73cb84f4dc6231537b08d..feb3201c85ce5df6d8786eaf2e4a0408e5890ec0 100644 (file)
@@ -120,7 +120,7 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
                                        ARRAY_SIZE(cclk_lp_parents),
                                        CLK_SET_RATE_PARENT,
                                        clk_base + CCLKLP_BURST_POLICY,
-                                       0, 4, 8, 9, NULL);
+                                       TEGRA_DIVIDER_2, 4, 8, 9, NULL);
                *dt_clk = clk;
        }
 
index 90d9d25f2228195308f328a9d7c05c1a5bbe5a40..80431f0fb2688f84557383b20ea39513ed2ffcc4 100644 (file)
@@ -682,12 +682,12 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
        [tegra_clk_timer] = { .dt_id = TEGRA114_CLK_TIMER, .present = true },
        [tegra_clk_uarta] = { .dt_id = TEGRA114_CLK_UARTA, .present = true },
        [tegra_clk_uartd] = { .dt_id = TEGRA114_CLK_UARTD, .present = true },
-       [tegra_clk_sdmmc2] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
+       [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
        [tegra_clk_i2s1] = { .dt_id = TEGRA114_CLK_I2S1, .present = true },
        [tegra_clk_i2c1] = { .dt_id = TEGRA114_CLK_I2C1, .present = true },
        [tegra_clk_ndflash] = { .dt_id = TEGRA114_CLK_NDFLASH, .present = true },
-       [tegra_clk_sdmmc1] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
-       [tegra_clk_sdmmc4] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
+       [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
+       [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
        [tegra_clk_pwm] = { .dt_id = TEGRA114_CLK_PWM, .present = true },
        [tegra_clk_i2s0] = { .dt_id = TEGRA114_CLK_I2S0, .present = true },
        [tegra_clk_i2s2] = { .dt_id = TEGRA114_CLK_I2S2, .present = true },
@@ -723,7 +723,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
        [tegra_clk_bsev] = { .dt_id = TEGRA114_CLK_BSEV, .present = true },
        [tegra_clk_i2c3] = { .dt_id = TEGRA114_CLK_I2C3, .present = true },
        [tegra_clk_sbc4_8] = { .dt_id = TEGRA114_CLK_SBC4, .present = true },
-       [tegra_clk_sdmmc3] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
+       [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
        [tegra_clk_owr] = { .dt_id = TEGRA114_CLK_OWR, .present = true },
        [tegra_clk_csite] = { .dt_id = TEGRA114_CLK_CSITE, .present = true },
        [tegra_clk_la] = { .dt_id = TEGRA114_CLK_LA, .present = true },
index aff86b5bc7455c190fbf5ebaf2be08c204262e26..166e02f16c8a25f28f4441584dc6e8babc448f3b 100644 (file)
@@ -516,11 +516,11 @@ static struct div_nmp pllp_nmp = {
 };
 
 static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
-       {12000000, 216000000, 432, 12, 1, 8},
-       {13000000, 216000000, 432, 13, 1, 8},
-       {16800000, 216000000, 360, 14, 1, 8},
-       {19200000, 216000000, 360, 16, 1, 8},
-       {26000000, 216000000, 432, 26, 1, 8},
+       {12000000, 408000000, 408, 12, 0, 8},
+       {13000000, 408000000, 408, 13, 0, 8},
+       {16800000, 408000000, 340, 14, 0, 8},
+       {19200000, 408000000, 340, 16, 0, 8},
+       {26000000, 408000000, 408, 26, 0, 8},
        {0, 0, 0, 0, 0, 0},
 };
 
@@ -570,6 +570,15 @@ static struct tegra_clk_pll_params pll_a_params = {
        .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
 };
 
+static struct div_nmp plld_nmp = {
+       .divm_shift = 0,
+       .divm_width = 5,
+       .divn_shift = 8,
+       .divn_width = 11,
+       .divp_shift = 20,
+       .divp_width = 3,
+};
+
 static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
        {12000000, 216000000, 864, 12, 4, 12},
        {13000000, 216000000, 864, 13, 4, 12},
@@ -603,19 +612,18 @@ static struct tegra_clk_pll_params pll_d_params = {
        .lock_mask = PLL_BASE_LOCK,
        .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
        .lock_delay = 1000,
-       .div_nmp = &pllp_nmp,
+       .div_nmp = &plld_nmp,
        .freq_table = pll_d_freq_table,
        .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
                 TEGRA_PLL_USE_LOCK,
 };
 
 static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = {
-       { 12000000, 148500000,  99, 1, 8},
-       { 12000000, 594000000,  99, 1, 1},
-       { 13000000, 594000000,  91, 1, 1},      /* actual: 591.5 MHz */
-       { 16800000, 594000000,  71, 1, 1},      /* actual: 596.4 MHz */
-       { 19200000, 594000000,  62, 1, 1},      /* actual: 595.2 MHz */
-       { 26000000, 594000000,  91, 2, 1},      /* actual: 591.5 MHz */
+       { 12000000, 594000000,  99, 1, 2},
+       { 13000000, 594000000,  91, 1, 2},      /* actual: 591.5 MHz */
+       { 16800000, 594000000,  71, 1, 2},      /* actual: 596.4 MHz */
+       { 19200000, 594000000,  62, 1, 2},      /* actual: 595.2 MHz */
+       { 26000000, 594000000,  91, 2, 2},      /* actual: 591.5 MHz */
        { 0, 0, 0, 0, 0, 0 },
 };
 
@@ -753,21 +761,19 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
        [tegra_clk_rtc] = { .dt_id = TEGRA124_CLK_RTC, .present = true },
        [tegra_clk_timer] = { .dt_id = TEGRA124_CLK_TIMER, .present = true },
        [tegra_clk_uarta] = { .dt_id = TEGRA124_CLK_UARTA, .present = true },
-       [tegra_clk_sdmmc2] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
+       [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
        [tegra_clk_i2s1] = { .dt_id = TEGRA124_CLK_I2S1, .present = true },
        [tegra_clk_i2c1] = { .dt_id = TEGRA124_CLK_I2C1, .present = true },
        [tegra_clk_ndflash] = { .dt_id = TEGRA124_CLK_NDFLASH, .present = true },
-       [tegra_clk_sdmmc1] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
-       [tegra_clk_sdmmc4] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
+       [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
+       [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
        [tegra_clk_pwm] = { .dt_id = TEGRA124_CLK_PWM, .present = true },
        [tegra_clk_i2s2] = { .dt_id = TEGRA124_CLK_I2S2, .present = true },
-       [tegra_clk_gr2d] = { .dt_id = TEGRA124_CLK_GR_2D, .present = true },
        [tegra_clk_usbd] = { .dt_id = TEGRA124_CLK_USBD, .present = true },
        [tegra_clk_isp_8] = { .dt_id = TEGRA124_CLK_ISP, .present = true },
-       [tegra_clk_gr3d] = { .dt_id = TEGRA124_CLK_GR_3D, .present = true },
        [tegra_clk_disp2] = { .dt_id = TEGRA124_CLK_DISP2, .present = true },
        [tegra_clk_disp1] = { .dt_id = TEGRA124_CLK_DISP1, .present = true },
-       [tegra_clk_host1x] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
+       [tegra_clk_host1x_8] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
        [tegra_clk_vcp] = { .dt_id = TEGRA124_CLK_VCP, .present = true },
        [tegra_clk_i2s0] = { .dt_id = TEGRA124_CLK_I2S0, .present = true },
        [tegra_clk_apbdma] = { .dt_id = TEGRA124_CLK_APBDMA, .present = true },
@@ -794,7 +800,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
        [tegra_clk_uartd] = { .dt_id = TEGRA124_CLK_UARTD, .present = true },
        [tegra_clk_i2c3] = { .dt_id = TEGRA124_CLK_I2C3, .present = true },
        [tegra_clk_sbc4] = { .dt_id = TEGRA124_CLK_SBC4, .present = true },
-       [tegra_clk_sdmmc3] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
+       [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
        [tegra_clk_pcie] = { .dt_id = TEGRA124_CLK_PCIE, .present = true },
        [tegra_clk_owr] = { .dt_id = TEGRA124_CLK_OWR, .present = true },
        [tegra_clk_afi] = { .dt_id = TEGRA124_CLK_AFI, .present = true },
@@ -1286,9 +1292,9 @@ static void __init tegra124_pll_init(void __iomem *clk_base,
        clk_register_clkdev(clk, "pll_d2", NULL);
        clks[TEGRA124_CLK_PLL_D2] = clk;
 
-       /* PLLD2_OUT0 ?? */
+       /* PLLD2_OUT0 */
        clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
-                                       CLK_SET_RATE_PARENT, 1, 2);
+                                       CLK_SET_RATE_PARENT, 1, 1);
        clk_register_clkdev(clk, "pll_d2_out0", NULL);
        clks[TEGRA124_CLK_PLL_D2_OUT0] = clk;
 
index dbace152b2faa9e4f1699b8369d935683900df89..dace2b1b5ae66dafab4fe4639e6291872491119d 100644 (file)
@@ -574,6 +574,8 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = {
        [tegra_clk_tvdac] = { .dt_id = TEGRA20_CLK_TVDAC, .present = true },
        [tegra_clk_vi_sensor] = { .dt_id = TEGRA20_CLK_VI_SENSOR, .present = true },
        [tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true },
+       [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true },
+       [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true },
 };
 
 static unsigned long tegra20_clk_measure_input_freq(void)
index 08ca8c9f41cdeb27f6e4bb4879b2912798e1a72e..199b52b7c3e1ad6e9d00102905a215137901b71d 100644 (file)
@@ -1109,12 +1109,27 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
                goto err_set_policy_cpu;
        }
 
+       /* related cpus should atleast have policy->cpus */
+       cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
+
+       /*
+        * affected cpus must always be the one, which are online. We aren't
+        * managing offline cpus here.
+        */
+       cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
+
+       if (!frozen) {
+               policy->user_policy.min = policy->min;
+               policy->user_policy.max = policy->max;
+       }
+
+       down_write(&policy->rwsem);
        write_lock_irqsave(&cpufreq_driver_lock, flags);
        for_each_cpu(j, policy->cpus)
                per_cpu(cpufreq_cpu_data, j) = policy;
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-       if (cpufreq_driver->get) {
+       if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
                policy->cur = cpufreq_driver->get(policy->cpu);
                if (!policy->cur) {
                        pr_err("%s: ->get() failed\n", __func__);
@@ -1162,20 +1177,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
                }
        }
 
-       /* related cpus should atleast have policy->cpus */
-       cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
-
-       /*
-        * affected cpus must always be the one, which are online. We aren't
-        * managing offline cpus here.
-        */
-       cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
-
-       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);
 
@@ -1206,6 +1207,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
                policy->user_policy.policy = policy->policy;
                policy->user_policy.governor = policy->governor;
        }
+       up_write(&policy->rwsem);
 
        kobject_uevent(&policy->kobj, KOBJ_ADD);
        up_read(&cpufreq_rwsem);
@@ -1323,8 +1325,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
        up_read(&policy->rwsem);
 
        if (cpu != policy->cpu) {
-               if (!frozen)
-                       sysfs_remove_link(&dev->kobj, "cpufreq");
+               sysfs_remove_link(&dev->kobj, "cpufreq");
        } else if (cpus > 1) {
                new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
                if (new_cpu >= 0) {
@@ -1547,23 +1548,16 @@ static unsigned int __cpufreq_get(unsigned int cpu)
  */
 unsigned int cpufreq_get(unsigned int cpu)
 {
-       struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
        unsigned int ret_freq = 0;
 
-       if (cpufreq_disabled() || !cpufreq_driver)
-               return -ENOENT;
-
-       BUG_ON(!policy);
-
-       if (!down_read_trylock(&cpufreq_rwsem))
-               return 0;
-
-       down_read(&policy->rwsem);
-
-       ret_freq = __cpufreq_get(cpu);
+       if (policy) {
+               down_read(&policy->rwsem);
+               ret_freq = __cpufreq_get(cpu);
+               up_read(&policy->rwsem);
 
-       up_read(&policy->rwsem);
-       up_read(&cpufreq_rwsem);
+               cpufreq_cpu_put(policy);
+       }
 
        return ret_freq;
 }
@@ -2149,7 +2143,7 @@ int cpufreq_update_policy(unsigned int cpu)
         * BIOS might change freq behind our back
         * -> ask driver for current freq and notify governors about a change
         */
-       if (cpufreq_driver->get) {
+       if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
                new_policy.cur = cpufreq_driver->get(cpu);
                if (!policy->cur) {
                        pr_debug("Driver did not initialize current freq");
index c788abf1c457cea63c1b60b7bbff637e5b303228..2cd36b9297f3de01a4b5f2ed246d738e123d7991 100644 (file)
 
 #define SAMPLE_COUNT           3
 
-#define BYT_RATIOS     0x66a
-#define BYT_VIDS        0x66b
+#define BYT_RATIOS             0x66a
+#define BYT_VIDS               0x66b
+#define BYT_TURBO_RATIOS       0x66c
 
-#define FRAC_BITS 8
+
+#define FRAC_BITS 6
 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
 #define fp_toint(X) ((X) >> FRAC_BITS)
+#define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS)
 
 static inline int32_t mul_fp(int32_t x, int32_t y)
 {
@@ -357,7 +360,7 @@ static int byt_get_min_pstate(void)
 {
        u64 value;
        rdmsrl(BYT_RATIOS, value);
-       return value & 0xFF;
+       return (value >> 8) & 0xFF;
 }
 
 static int byt_get_max_pstate(void)
@@ -367,6 +370,13 @@ static int byt_get_max_pstate(void)
        return (value >> 16) & 0xFF;
 }
 
+static int byt_get_turbo_pstate(void)
+{
+       u64 value;
+       rdmsrl(BYT_TURBO_RATIOS, value);
+       return value & 0x3F;
+}
+
 static void byt_set_pstate(struct cpudata *cpudata, int pstate)
 {
        u64 val;
@@ -469,7 +479,7 @@ static struct cpu_defaults byt_params = {
        .funcs = {
                .get_max = byt_get_max_pstate,
                .get_min = byt_get_min_pstate,
-               .get_turbo = byt_get_max_pstate,
+               .get_turbo = byt_get_turbo_pstate,
                .set = byt_set_pstate,
                .get_vid = byt_get_vid,
        },
@@ -547,18 +557,20 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
 static inline void intel_pstate_calc_busy(struct cpudata *cpu,
                                        struct sample *sample)
 {
-       u64 core_pct;
-       u64 c0_pct;
+       int32_t core_pct;
+       int32_t c0_pct;
 
-       core_pct = div64_u64(sample->aperf * 100, sample->mperf);
+       core_pct = div_fp(int_tofp((sample->aperf)),
+                       int_tofp((sample->mperf)));
+       core_pct = mul_fp(core_pct, int_tofp(100));
+       FP_ROUNDUP(core_pct);
+
+       c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc));
 
-       c0_pct = div64_u64(sample->mperf * 100, sample->tsc);
        sample->freq = fp_toint(
-               mul_fp(int_tofp(cpu->pstate.max_pstate),
-                       int_tofp(core_pct * 1000)));
+               mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct));
 
-       sample->core_pct_busy = mul_fp(int_tofp(core_pct),
-                               div_fp(int_tofp(c0_pct + 1), int_tofp(100)));
+       sample->core_pct_busy = mul_fp(core_pct, c0_pct);
 }
 
 static inline void intel_pstate_sample(struct cpudata *cpu)
@@ -570,6 +582,10 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
        rdmsrl(MSR_IA32_MPERF, mperf);
        tsc = native_read_tsc();
 
+       aperf = aperf >> FRAC_BITS;
+       mperf = mperf >> FRAC_BITS;
+       tsc = tsc >> FRAC_BITS;
+
        cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
        cpu->samples[cpu->sample_ptr].aperf = aperf;
        cpu->samples[cpu->sample_ptr].mperf = mperf;
@@ -601,7 +617,8 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
        core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy;
        max_pstate = int_tofp(cpu->pstate.max_pstate);
        current_pstate = int_tofp(cpu->pstate.current_pstate);
-       return mul_fp(core_busy, div_fp(max_pstate, current_pstate));
+       core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
+       return FP_ROUNDUP(core_busy);
 }
 
 static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
index e10b646634d77ff3a4bcf0c54d154a91c7c35805..6684e0342792517577fde32d56542b3ad84d15af 100644 (file)
@@ -1076,7 +1076,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
 {
        struct powernow_k8_data *data;
        struct init_on_cpu init_on_cpu;
-       int rc;
+       int rc, cpu;
 
        smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1);
        if (rc)
@@ -1140,7 +1140,9 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
        pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n",
                 data->currfid, data->currvid);
 
-       per_cpu(powernow_data, pol->cpu) = data;
+       /* Point all the CPUs in this policy to the same data */
+       for_each_cpu(cpu, pol->cpus)
+               per_cpu(powernow_data, cpu) = data;
 
        return 0;
 
@@ -1155,6 +1157,7 @@ err_out:
 static int powernowk8_cpu_exit(struct cpufreq_policy *pol)
 {
        struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
+       int cpu;
 
        if (!data)
                return -EINVAL;
@@ -1165,7 +1168,8 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol)
 
        kfree(data->powernow_table);
        kfree(data);
-       per_cpu(powernow_data, pol->cpu) = NULL;
+       for_each_cpu(cpu, pol->cpus)
+               per_cpu(powernow_data, cpu) = NULL;
 
        return 0;
 }
index 4e7918339b1263a2720c3da11d271714dd9669ad..19041cefabb1c0ce8649ed8cf5ea41707fa7824f 100644 (file)
@@ -449,6 +449,7 @@ static const struct of_device_id sdma_dt_ids[] = {
        { .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, },
        { .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, },
        { .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
+       { .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sdma_dt_ids);
index 87529181efccb9851467cc04be04bd91fecb15b3..4e3549a161324f29159775312b3c9d8075914359 100644 (file)
@@ -77,7 +77,8 @@ static irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
        attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
        for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) {
                chan = ioat_chan_by_index(instance, bit);
-               tasklet_schedule(&chan->cleanup_task);
+               if (test_bit(IOAT_RUN, &chan->state))
+                       tasklet_schedule(&chan->cleanup_task);
        }
 
        writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
@@ -93,7 +94,8 @@ static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
 {
        struct ioat_chan_common *chan = data;
 
-       tasklet_schedule(&chan->cleanup_task);
+       if (test_bit(IOAT_RUN, &chan->state))
+               tasklet_schedule(&chan->cleanup_task);
 
        return IRQ_HANDLED;
 }
@@ -116,7 +118,6 @@ void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *c
        chan->timer.function = device->timer_fn;
        chan->timer.data = data;
        tasklet_init(&chan->cleanup_task, device->cleanup_fn, data);
-       tasklet_disable(&chan->cleanup_task);
 }
 
 /**
@@ -354,13 +355,49 @@ static int ioat1_dma_alloc_chan_resources(struct dma_chan *c)
        writel(((u64) chan->completion_dma) >> 32,
               chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
 
-       tasklet_enable(&chan->cleanup_task);
+       set_bit(IOAT_RUN, &chan->state);
        ioat1_dma_start_null_desc(ioat);  /* give chain to dma device */
        dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n",
                __func__, ioat->desccount);
        return ioat->desccount;
 }
 
+void ioat_stop(struct ioat_chan_common *chan)
+{
+       struct ioatdma_device *device = chan->device;
+       struct pci_dev *pdev = device->pdev;
+       int chan_id = chan_num(chan);
+       struct msix_entry *msix;
+
+       /* 1/ stop irq from firing tasklets
+        * 2/ stop the tasklet from re-arming irqs
+        */
+       clear_bit(IOAT_RUN, &chan->state);
+
+       /* flush inflight interrupts */
+       switch (device->irq_mode) {
+       case IOAT_MSIX:
+               msix = &device->msix_entries[chan_id];
+               synchronize_irq(msix->vector);
+               break;
+       case IOAT_MSI:
+       case IOAT_INTX:
+               synchronize_irq(pdev->irq);
+               break;
+       default:
+               break;
+       }
+
+       /* flush inflight timers */
+       del_timer_sync(&chan->timer);
+
+       /* flush inflight tasklet runs */
+       tasklet_kill(&chan->cleanup_task);
+
+       /* final cleanup now that everything is quiesced and can't re-arm */
+       device->cleanup_fn((unsigned long) &chan->common);
+}
+
 /**
  * ioat1_dma_free_chan_resources - release all the descriptors
  * @chan: the channel to be cleaned
@@ -379,9 +416,7 @@ static void ioat1_dma_free_chan_resources(struct dma_chan *c)
        if (ioat->desccount == 0)
                return;
 
-       tasklet_disable(&chan->cleanup_task);
-       del_timer_sync(&chan->timer);
-       ioat1_cleanup(ioat);
+       ioat_stop(chan);
 
        /* Delay 100ms after reset to allow internal DMA logic to quiesce
         * before removing DMA descriptor resources.
@@ -526,8 +561,11 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest,
 static void ioat1_cleanup_event(unsigned long data)
 {
        struct ioat_dma_chan *ioat = to_ioat_chan((void *) data);
+       struct ioat_chan_common *chan = &ioat->base;
 
        ioat1_cleanup(ioat);
+       if (!test_bit(IOAT_RUN, &chan->state))
+               return;
        writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
 }
 
index 11fb877ddca9a9b0888d23952dea8fb48245b617..e982f00a984399a3838f7b47ef2e21a2aab84495 100644 (file)
@@ -356,6 +356,7 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan,
 void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
 void ioat_kobject_del(struct ioatdma_device *device);
 int ioat_dma_setup_interrupts(struct ioatdma_device *device);
+void ioat_stop(struct ioat_chan_common *chan);
 extern const struct sysfs_ops ioat_sysfs_ops;
 extern struct ioat_sysfs_entry ioat_version_attr;
 extern struct ioat_sysfs_entry ioat_cap_attr;
index 5d3affe7e976165ec5576ac8c6551dd438af7786..8d1058085eeb85beb3fb2d6ab88c57160ef0cf15 100644 (file)
@@ -190,8 +190,11 @@ static void ioat2_cleanup(struct ioat2_dma_chan *ioat)
 void ioat2_cleanup_event(unsigned long data)
 {
        struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
+       struct ioat_chan_common *chan = &ioat->base;
 
        ioat2_cleanup(ioat);
+       if (!test_bit(IOAT_RUN, &chan->state))
+               return;
        writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
 }
 
@@ -553,10 +556,10 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
        ioat->issued = 0;
        ioat->tail = 0;
        ioat->alloc_order = order;
+       set_bit(IOAT_RUN, &chan->state);
        spin_unlock_bh(&ioat->prep_lock);
        spin_unlock_bh(&chan->cleanup_lock);
 
-       tasklet_enable(&chan->cleanup_task);
        ioat2_start_null_desc(ioat);
 
        /* check that we got off the ground */
@@ -566,7 +569,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
        } while (i++ < 20 && !is_ioat_active(status) && !is_ioat_idle(status));
 
        if (is_ioat_active(status) || is_ioat_idle(status)) {
-               set_bit(IOAT_RUN, &chan->state);
                return 1 << ioat->alloc_order;
        } else {
                u32 chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
@@ -809,11 +811,8 @@ void ioat2_free_chan_resources(struct dma_chan *c)
        if (!ioat->ring)
                return;
 
-       tasklet_disable(&chan->cleanup_task);
-       del_timer_sync(&chan->timer);
-       device->cleanup_fn((unsigned long) c);
+       ioat_stop(chan);
        device->reset_hw(chan);
-       clear_bit(IOAT_RUN, &chan->state);
 
        spin_lock_bh(&chan->cleanup_lock);
        spin_lock_bh(&ioat->prep_lock);
index 820817e97e626a498561a9e5f0f3a61f22ffc9fa..b9b38a1cf92fbdc4147e70af93508f0d9caf6867 100644 (file)
@@ -464,8 +464,11 @@ static void ioat3_cleanup(struct ioat2_dma_chan *ioat)
 static void ioat3_cleanup_event(unsigned long data)
 {
        struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
+       struct ioat_chan_common *chan = &ioat->base;
 
        ioat3_cleanup(ioat);
+       if (!test_bit(IOAT_RUN, &chan->state))
+               return;
        writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
 }
 
index 00a2de957b234da060fe5e03592b171f50fa53d1..bf18c786ed40fbaae2a487246df5da85457fbec1 100644 (file)
@@ -1641,6 +1641,7 @@ static void dma_tasklet(unsigned long data)
        struct d40_chan *d40c = (struct d40_chan *) data;
        struct d40_desc *d40d;
        unsigned long flags;
+       bool callback_active;
        dma_async_tx_callback callback;
        void *callback_param;
 
@@ -1668,6 +1669,7 @@ static void dma_tasklet(unsigned long data)
        }
 
        /* Callback to client */
+       callback_active = !!(d40d->txd.flags & DMA_PREP_INTERRUPT);
        callback = d40d->txd.callback;
        callback_param = d40d->txd.callback_param;
 
@@ -1690,7 +1692,7 @@ static void dma_tasklet(unsigned long data)
 
        spin_unlock_irqrestore(&d40c->lock, flags);
 
-       if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT))
+       if (callback_active && callback)
                callback(callback_param);
 
        return;
index d63f4798f7d09127872f97ed925a5af64a75f81f..57e96a3350f0595ab002a5ff1285d85b44dd6e3f 100644 (file)
@@ -943,33 +943,35 @@ static int i7300_get_devices(struct mem_ctl_info *mci)
 
        /* Attempt to 'get' the MCH register we want */
        pdev = NULL;
-       while (!pvt->pci_dev_16_1_fsb_addr_map ||
-              !pvt->pci_dev_16_2_fsb_err_regs) {
-               pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                     PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev);
-               if (!pdev) {
-                       /* End of list, leave */
-                       i7300_printk(KERN_ERR,
-                               "'system address,Process Bus' "
-                               "device not found:"
-                               "vendor 0x%x device 0x%x ERR funcs "
-                               "(broken BIOS?)\n",
-                               PCI_VENDOR_ID_INTEL,
-                               PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
-                       goto error;
-               }
-
+       while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                     PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
+                                     pdev))) {
                /* Store device 16 funcs 1 and 2 */
                switch (PCI_FUNC(pdev->devfn)) {
                case 1:
-                       pvt->pci_dev_16_1_fsb_addr_map = pdev;
+                       if (!pvt->pci_dev_16_1_fsb_addr_map)
+                               pvt->pci_dev_16_1_fsb_addr_map =
+                                                       pci_dev_get(pdev);
                        break;
                case 2:
-                       pvt->pci_dev_16_2_fsb_err_regs = pdev;
+                       if (!pvt->pci_dev_16_2_fsb_err_regs)
+                               pvt->pci_dev_16_2_fsb_err_regs =
+                                                       pci_dev_get(pdev);
                        break;
                }
        }
 
+       if (!pvt->pci_dev_16_1_fsb_addr_map ||
+           !pvt->pci_dev_16_2_fsb_err_regs) {
+               /* At least one device was not found */
+               i7300_printk(KERN_ERR,
+                       "'system address,Process Bus' device not found:"
+                       "vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n",
+                       PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
+               goto error;
+       }
+
        edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
                 pci_name(pvt->pci_dev_16_0_fsb_ctlr),
                 pvt->pci_dev_16_0_fsb_ctlr->vendor,
index 87533ca7752e0105683210913f83731a9b988aab..d871275196f6f04b6542e4941ee433e41fcfdf64 100644 (file)
@@ -1334,14 +1334,19 @@ static int i7core_get_onedevice(struct pci_dev **prev,
         * is at addr 8086:2c40, instead of 8086:2c41. So, we need
         * to probe for the alternate address in case of failure
         */
-       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
+       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) {
+               pci_dev_get(*prev);     /* pci_get_device will put it */
                pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                      PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
+       }
 
-       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
+       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE &&
+           !pdev) {
+               pci_dev_get(*prev);     /* pci_get_device will put it */
                pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                      PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
                                      *prev);
+       }
 
        if (!pdev) {
                if (*prev) {
index c20602f601ee22732635aa3fa04fe94e44ed6020..98a14f6143a7087accee9c5d2b127c99c300b81d 100644 (file)
@@ -222,27 +222,19 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
        struct snd_soc_dapm_context *dapm = arizona->dapm;
        int ret;
 
-       mutex_lock(&dapm->card->dapm_mutex);
-
        ret = snd_soc_dapm_force_enable_pin(dapm, widget);
        if (ret != 0)
                dev_warn(arizona->dev, "Failed to enable %s: %d\n",
                         widget, ret);
 
-       mutex_unlock(&dapm->card->dapm_mutex);
-
        snd_soc_dapm_sync(dapm);
 
        if (!arizona->pdata.micd_force_micbias) {
-               mutex_lock(&dapm->card->dapm_mutex);
-
                ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
                if (ret != 0)
                        dev_warn(arizona->dev, "Failed to disable %s: %d\n",
                                 widget, ret);
 
-               mutex_unlock(&dapm->card->dapm_mutex);
-
                snd_soc_dapm_sync(dapm);
        }
 }
@@ -304,16 +296,12 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
                                 ARIZONA_MICD_ENA, 0,
                                 &change);
 
-       mutex_lock(&dapm->card->dapm_mutex);
-
        ret = snd_soc_dapm_disable_pin(dapm, widget);
        if (ret != 0)
                dev_warn(arizona->dev,
                         "Failed to disable %s: %d\n",
                         widget, ret);
 
-       mutex_unlock(&dapm->card->dapm_mutex);
-
        snd_soc_dapm_sync(dapm);
 
        if (info->micd_reva) {
index de4aa409abe2988d8dc5b421e969ab5256fb4009..2c6d5e118ac129e5ab9c24f09557b27e3248f3ea 100644 (file)
@@ -916,7 +916,7 @@ static int lookup_existing_device(struct device *dev, void *data)
                old->config_rom_retries = 0;
                fw_notice(card, "rediscovered device %s\n", dev_name(dev));
 
-               PREPARE_DELAYED_WORK(&old->work, fw_device_update);
+               old->workfn = fw_device_update;
                fw_schedule_device_work(old, 0);
 
                if (current_node == card->root_node)
@@ -1075,7 +1075,7 @@ static void fw_device_init(struct work_struct *work)
        if (atomic_cmpxchg(&device->state,
                           FW_DEVICE_INITIALIZING,
                           FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
-               PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+               device->workfn = fw_device_shutdown;
                fw_schedule_device_work(device, SHUTDOWN_DELAY);
        } else {
                fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
@@ -1196,13 +1196,20 @@ static void fw_device_refresh(struct work_struct *work)
                  dev_name(&device->device), fw_rcode_string(ret));
  gone:
        atomic_set(&device->state, FW_DEVICE_GONE);
-       PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+       device->workfn = fw_device_shutdown;
        fw_schedule_device_work(device, SHUTDOWN_DELAY);
  out:
        if (node_id == card->root_node->node_id)
                fw_schedule_bm_work(card, 0);
 }
 
+static void fw_device_workfn(struct work_struct *work)
+{
+       struct fw_device *device = container_of(to_delayed_work(work),
+                                               struct fw_device, work);
+       device->workfn(work);
+}
+
 void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
 {
        struct fw_device *device;
@@ -1252,7 +1259,8 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                 * power-up after getting plugged in.  We schedule the
                 * first config rom scan half a second after bus reset.
                 */
-               INIT_DELAYED_WORK(&device->work, fw_device_init);
+               device->workfn = fw_device_init;
+               INIT_DELAYED_WORK(&device->work, fw_device_workfn);
                fw_schedule_device_work(device, INITIAL_DELAY);
                break;
 
@@ -1268,7 +1276,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                if (atomic_cmpxchg(&device->state,
                            FW_DEVICE_RUNNING,
                            FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
-                       PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
+                       device->workfn = fw_device_refresh;
                        fw_schedule_device_work(device,
                                device->is_local ? 0 : INITIAL_DELAY);
                }
@@ -1283,7 +1291,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                smp_wmb();  /* update node_id before generation */
                device->generation = card->generation;
                if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
-                       PREPARE_DELAYED_WORK(&device->work, fw_device_update);
+                       device->workfn = fw_device_update;
                        fw_schedule_device_work(device, 0);
                }
                break;
@@ -1308,7 +1316,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                device = node->data;
                if (atomic_xchg(&device->state,
                                FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
-                       PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+                       device->workfn = fw_device_shutdown;
                        fw_schedule_device_work(device,
                                list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
                }
index 6b895986dc225115573add201958e60897934853..4af0a7bad7f21561cc4e7a29031c238a34f0135d 100644 (file)
@@ -929,8 +929,6 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
        if (rcode == RCODE_COMPLETE) {
                fwnet_transmit_packet_done(ptask);
        } else {
-               fwnet_transmit_packet_failed(ptask);
-
                if (printk_timed_ratelimit(&j,  1000) || rcode != last_rcode) {
                        dev_err(&ptask->dev->netdev->dev,
                                "fwnet_write_complete failed: %x (skipped %d)\n",
@@ -938,8 +936,10 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
 
                        errors_skipped = 0;
                        last_rcode = rcode;
-               } else
+               } else {
                        errors_skipped++;
+               }
+               fwnet_transmit_packet_failed(ptask);
        }
 }
 
index 6f74d8d3f70015a089f02948294454863cb6bcd7..8db66321956068701cde997e0bc25e167e781eb3 100644 (file)
@@ -290,7 +290,6 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
 #define QUIRK_NO_MSI                   0x10
 #define QUIRK_TI_SLLZ059               0x20
 #define QUIRK_IR_WAKE                  0x40
-#define QUIRK_PHY_LCTRL_TIMEOUT                0x80
 
 /* In case of multiple matches in ohci_quirks[], only the first one is used. */
 static const struct {
@@ -303,10 +302,7 @@ static const struct {
                QUIRK_BE_HEADERS},
 
        {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6,
-               QUIRK_PHY_LCTRL_TIMEOUT | QUIRK_NO_MSI},
-
-       {PCI_VENDOR_ID_ATT, PCI_ANY_ID, PCI_ANY_ID,
-               QUIRK_PHY_LCTRL_TIMEOUT},
+               QUIRK_NO_MSI},
 
        {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID,
                QUIRK_RESET_PACKET},
@@ -353,7 +349,6 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
        ", disable MSI = "              __stringify(QUIRK_NO_MSI)
        ", TI SLLZ059 erratum = "       __stringify(QUIRK_TI_SLLZ059)
        ", IR wake unreliable = "       __stringify(QUIRK_IR_WAKE)
-       ", phy LCtrl timeout = "        __stringify(QUIRK_PHY_LCTRL_TIMEOUT)
        ")");
 
 #define OHCI_PARAM_DEBUG_AT_AR         1
@@ -2299,9 +2294,6 @@ static int ohci_enable(struct fw_card *card,
         * TI TSB82AA2 + TSB81BA3(A) cards signal LPS enabled early but
         * cannot actually use the phy at that time.  These need tens of
         * millisecods pause between LPS write and first phy access too.
-        *
-        * But do not wait for 50msec on Agere/LSI cards.  Their phy
-        * arbitration state machine may time out during such a long wait.
         */
 
        reg_write(ohci, OHCI1394_HCControlSet,
@@ -2309,11 +2301,8 @@ static int ohci_enable(struct fw_card *card,
                  OHCI1394_HCControl_postedWriteEnable);
        flush_writes(ohci);
 
-       if (!(ohci->quirks & QUIRK_PHY_LCTRL_TIMEOUT))
+       for (lps = 0, i = 0; !lps && i < 3; i++) {
                msleep(50);
-
-       for (lps = 0, i = 0; !lps && i < 150; i++) {
-               msleep(1);
                lps = reg_read(ohci, OHCI1394_HCControlSet) &
                      OHCI1394_HCControl_LPS;
        }
index 281029daf98c7ea291886d46ecf05378bfa98718..7aef911fdc716d4874b7152b3c0d6e27bc8c1642 100644 (file)
@@ -146,6 +146,7 @@ struct sbp2_logical_unit {
         */
        int generation;
        int retries;
+       work_func_t workfn;
        struct delayed_work work;
        bool has_sdev;
        bool blocked;
@@ -864,7 +865,7 @@ static void sbp2_login(struct work_struct *work)
        /* set appropriate retry limit(s) in BUSY_TIMEOUT register */
        sbp2_set_busy_timeout(lu);
 
-       PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
+       lu->workfn = sbp2_reconnect;
        sbp2_agent_reset(lu);
 
        /* This was a re-login. */
@@ -918,7 +919,7 @@ static void sbp2_login(struct work_struct *work)
         * If a bus reset happened, sbp2_update will have requeued
         * lu->work already.  Reset the work from reconnect to login.
         */
-       PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+       lu->workfn = sbp2_login;
 }
 
 static void sbp2_reconnect(struct work_struct *work)
@@ -952,7 +953,7 @@ static void sbp2_reconnect(struct work_struct *work)
                    lu->retries++ >= 5) {
                        dev_err(tgt_dev(tgt), "failed to reconnect\n");
                        lu->retries = 0;
-                       PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+                       lu->workfn = sbp2_login;
                }
                sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
 
@@ -972,6 +973,13 @@ static void sbp2_reconnect(struct work_struct *work)
        sbp2_conditionally_unblock(lu);
 }
 
+static void sbp2_lu_workfn(struct work_struct *work)
+{
+       struct sbp2_logical_unit *lu = container_of(to_delayed_work(work),
+                                               struct sbp2_logical_unit, work);
+       lu->workfn(work);
+}
+
 static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
 {
        struct sbp2_logical_unit *lu;
@@ -998,7 +1006,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
        lu->blocked  = false;
        ++tgt->dont_block;
        INIT_LIST_HEAD(&lu->orb_list);
-       INIT_DELAYED_WORK(&lu->work, sbp2_login);
+       lu->workfn = sbp2_login;
+       INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn);
 
        list_add_tail(&lu->link, &tgt->lu_list);
        return 0;
index ee5b47904130bdaab802fb3ddb6bce0f5f73c215..9bb2cbd5c9f265e421ded04a69b72f37141a2663 100644 (file)
@@ -27,7 +27,7 @@ FMC_PARAM_BUSID(fwe_drv);
 /* The "file=" is like the generic "gateware=" used elsewhere */
 static char *fwe_file[FMC_MAX_CARDS];
 static int fwe_file_n;
-module_param_array_named(file, fwe_file, charp, &fwe_file_n, 444);
+module_param_array_named(file, fwe_file, charp, &fwe_file_n, 0444);
 
 static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw,
        int write)
index acf3a36c9ebc453737b1a849aa6715f41b241d68..32982da82694be753d1072c90136d842a8a866ec 100644 (file)
@@ -68,15 +68,7 @@ void __armada_drm_queue_unref_work(struct drm_device *dev,
 {
        struct armada_private *priv = dev->dev_private;
 
-       /*
-        * Yes, we really must jump through these hoops just to store a
-        * _pointer_ to something into the kfifo.  This is utterly insane
-        * and idiotic, because it kfifo requires the _data_ pointed to by
-        * the pointer const, not the pointer itself.  Not only that, but
-        * you have to pass a pointer _to_ the pointer you want stored.
-        */
-       const struct drm_framebuffer *silly_api_alert = fb;
-       WARN_ON(!kfifo_put(&priv->fb_unref, &silly_api_alert));
+       WARN_ON(!kfifo_put(&priv->fb_unref, fb));
        schedule_work(&priv->fb_unref_work);
 }
 
index c8fcf12019f09c1eaffff1d72ea72c74714325e2..5f8b0c2b9a4461d2e07b1d7a3abb25f69837fc90 100644 (file)
@@ -2,6 +2,7 @@ config DRM_BOCHS
        tristate "DRM Support for bochs dispi vga interface (qemu stdvga)"
        depends on DRM && PCI
        select DRM_KMS_HELPER
+       select DRM_KMS_FB_HELPER
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
index 04f1f02c4019f57873caeb0c70fea14e0816ddeb..ec7bb0fc71bcfc8c19c2231c9bb0e3165f89e047 100644 (file)
@@ -403,7 +403,7 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 void intel_detect_pch(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct pci_dev *pch;
+       struct pci_dev *pch = NULL;
 
        /* In all current cases, num_pipes is equivalent to the PCH_NOP setting
         * (which really amounts to a PCH but no South Display).
@@ -424,12 +424,9 @@ void intel_detect_pch(struct drm_device *dev)
         * all the ISA bridge devices and check for the first match, instead
         * of only checking the first one.
         */
-       pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
-       while (pch) {
-               struct pci_dev *curr = pch;
+       while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) {
                if (pch->vendor == PCI_VENDOR_ID_INTEL) {
-                       unsigned short id;
-                       id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
+                       unsigned short id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
                        dev_priv->pch_id = id;
 
                        if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
@@ -461,18 +458,16 @@ void intel_detect_pch(struct drm_device *dev)
                                DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
                                WARN_ON(!IS_HASWELL(dev));
                                WARN_ON(!IS_ULT(dev));
-                       } else {
-                               goto check_next;
-                       }
-                       pci_dev_put(pch);
+                       } else
+                               continue;
+
                        break;
                }
-check_next:
-               pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr);
-               pci_dev_put(curr);
        }
        if (!pch)
-               DRM_DEBUG_KMS("No PCH found?\n");
+               DRM_DEBUG_KMS("No PCH found.\n");
+
+       pci_dev_put(pch);
 }
 
 bool i915_semaphore_is_enabled(struct drm_device *dev)
index 1a24e84f231578ae772d40ad75adda4c356b8d68..d58b4e287e3289a278741522a09baeaca584be0b 100644 (file)
@@ -82,9 +82,22 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
        r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size,
                                    "Graphics Stolen Memory");
        if (r == NULL) {
-               DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
-                         base, base + (uint32_t)dev_priv->gtt.stolen_size);
-               base = 0;
+               /*
+                * One more attempt but this time requesting region from
+                * base + 1, as we have seen that this resolves the region
+                * conflict with the PCI Bus.
+                * This is a BIOS w/a: Some BIOS wrap stolen in the root
+                * PCI bus, but have an off-by-one error. Hence retry the
+                * reservation starting from 1 instead of 0.
+                */
+               r = devm_request_mem_region(dev->dev, base + 1,
+                                           dev_priv->gtt.stolen_size - 1,
+                                           "Graphics Stolen Memory");
+               if (r == NULL) {
+                       DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
+                                 base, base + (uint32_t)dev_priv->gtt.stolen_size);
+                       base = 0;
+               }
        }
 
        return base;
index 4c1672809493c795714bc3eddaa1238c258451ed..9b8a7c7ea7fc1925610b4dcb11ca9f768057fd41 100644 (file)
@@ -1092,12 +1092,12 @@ static void assert_cursor(struct drm_i915_private *dev_priv,
        struct drm_device *dev = dev_priv->dev;
        bool cur_state;
 
-       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
-               cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
-       else if (IS_845G(dev) || IS_I865G(dev))
+       if (IS_845G(dev) || IS_I865G(dev))
                cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
-       else
+       else if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev))
                cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
+       else
+               cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
 
        WARN(cur_state != state,
             "cursor on pipe %c assertion failure (expected %s, current %s)\n",
index 6db0d9d17f47e7b5ce5c43a7aa7795de71ea6346..ee3181ebcc9236078835ee18a48fe86c97525ff9 100644 (file)
@@ -845,7 +845,7 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
 {
        struct drm_device *dev = intel_hdmi_to_dev(hdmi);
 
-       if (IS_G4X(dev))
+       if (!hdmi->has_hdmi_sink || IS_G4X(dev))
                return 165000;
        else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)
                return 300000;
@@ -899,8 +899,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         * outputs. We also need to check that the higher clock still fits
         * within limits.
         */
-       if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= portclock_limit
-           && HAS_PCH_SPLIT(dev)) {
+       if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink &&
+           clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
 
index 350de359123af9cbd42354c182424f356281aa16..079ea38f14d9b4b54092a1ebeca4cd77dac27cec 100644 (file)
@@ -698,7 +698,7 @@ static void i9xx_enable_backlight(struct intel_connector *connector)
                freq /= 0xff;
 
        ctl = freq << 17;
-       if (IS_GEN2(dev) && panel->backlight.combination_mode)
+       if (panel->backlight.combination_mode)
                ctl |= BLM_LEGACY_MODE;
        if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
                ctl |= BLM_POLARITY_PNV;
@@ -979,7 +979,7 @@ static int i9xx_setup_backlight(struct intel_connector *connector)
 
        ctl = I915_READ(BLC_PWM_CTL);
 
-       if (IS_GEN2(dev))
+       if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev))
                panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
 
        if (IS_PINEVIEW(dev))
index d77cc81900f92100ba2f61d7130bc9b0b60454b5..e1fc35a726564cc9f3526231780672d09d151838 100644 (file)
@@ -3493,6 +3493,8 @@ static void valleyview_setup_pctx(struct drm_device *dev)
        u32 pcbr;
        int pctx_size = 24*1024;
 
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
        pcbr = I915_READ(VLV_PCBR);
        if (pcbr) {
                /* BIOS set it up already, grab the pre-alloc'd space */
@@ -3542,8 +3544,6 @@ static void valleyview_enable_rps(struct drm_device *dev)
                I915_WRITE(GTFIFODBG, gtfifodbg);
        }
 
-       valleyview_setup_pctx(dev);
-
        /* If VLV, Forcewake all wells, else re-direct to regular path */
        gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
@@ -4395,6 +4395,8 @@ void intel_enable_gt_powersave(struct drm_device *dev)
                ironlake_enable_rc6(dev);
                intel_init_emon(dev);
        } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+               if (IS_VALLEYVIEW(dev))
+                       valleyview_setup_pctx(dev);
                /*
                 * PCU communication is slow and this doesn't need to be
                 * done at any specific time, so do this out of our fast path
index 4ef83df2b246fb335dc8ce05bafead80ed7ac180..83face3f608f020f70d7d11dda363c5817102238 100644 (file)
@@ -106,6 +106,29 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
        return 0;
 }
 
+/*
+ * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special
+ * requirements on the fourth parameter, so a private implementation
+ * instead of using acpi_check_dsm().
+ */
+static int nouveau_check_optimus_dsm(acpi_handle handle)
+{
+       int result;
+
+       /*
+        * Function 0 returns a Buffer containing available functions.
+        * The args parameter is ignored for function 0, so just put 0 in it
+        */
+       if (nouveau_optimus_dsm(handle, 0, 0, &result))
+               return 0;
+
+       /*
+        * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
+        * If the n-th bit is enabled, function n is supported
+        */
+       return result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS);
+}
+
 static int nouveau_dsm(acpi_handle handle, int func, int arg)
 {
        int ret = 0;
@@ -207,8 +230,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
                           1 << NOUVEAU_DSM_POWER))
                retval |= NOUVEAU_DSM_HAS_MUX;
 
-       if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100,
-                          1 << NOUVEAU_DSM_OPTIMUS_CAPS))
+       if (nouveau_check_optimus_dsm(dhandle))
                retval |= NOUVEAU_DSM_HAS_OPT;
 
        if (retval & NOUVEAU_DSM_HAS_OPT) {
index 0d19f4f94d5a065b2687399b559aaf43f4a5c587..daa4dd375ab15367266d6f0041af84386d6699bb 100644 (file)
@@ -1774,6 +1774,20 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                        return ATOM_PPLL1;
                DRM_ERROR("unable to allocate a PPLL\n");
                return ATOM_PPLL_INVALID;
+       } else if (ASIC_IS_DCE41(rdev)) {
+               /* Don't share PLLs on DCE4.1 chips */
+               if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
+                       if (rdev->clock.dp_extclk)
+                               /* skip PPLL programming if using ext clock */
+                               return ATOM_PPLL_INVALID;
+               }
+               pll_in_use = radeon_get_pll_use_mask(crtc);
+               if (!(pll_in_use & (1 << ATOM_PPLL1)))
+                       return ATOM_PPLL1;
+               if (!(pll_in_use & (1 << ATOM_PPLL2)))
+                       return ATOM_PPLL2;
+               DRM_ERROR("unable to allocate a PPLL\n");
+               return ATOM_PPLL_INVALID;
        } else if (ASIC_IS_DCE4(rdev)) {
                /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
                 * depending on the asic:
@@ -1801,7 +1815,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                                if (pll != ATOM_PPLL_INVALID)
                                        return pll;
                        }
-               } else if (!ASIC_IS_DCE41(rdev)) { /* Don't share PLLs on DCE4.1 chips */
+               } else {
                        /* use the same PPLL for all monitors with the same clock */
                        pll = radeon_get_shared_nondp_ppll(crtc);
                        if (pll != ATOM_PPLL_INVALID)
index 2cec2ab02f80c193ce929393cd3d0c86bdd3d7c9..607dc14d195e3540f103bf798d2e6f0e10e5634f 100644 (file)
@@ -1314,7 +1314,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                        }
                        if (is_dp)
                                args.v5.ucLaneNum = dp_lane_count;
-                       else if (radeon_encoder->pixel_clock > 165000)
+                       else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
                                args.v5.ucLaneNum = 8;
                        else
                                args.v5.ucLaneNum = 4;
index e6419ca7cd375d6958ebcd339fb68a004c56cd1a..bbb17841a9e57ad2fdc44425a26d658848892f4c 100644 (file)
@@ -3046,7 +3046,7 @@ static u32 cik_create_bitmask(u32 bit_width)
 }
 
 /**
- * cik_select_se_sh - select which SE, SH to address
+ * cik_get_rb_disabled - computes the mask of disabled RBs
  *
  * @rdev: radeon_device pointer
  * @max_rb_num: max RBs (render backends) for the asic
@@ -4134,8 +4134,11 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable)
 {
        if (enable)
                WREG32(CP_MEC_CNTL, 0);
-       else
+       else {
                WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT));
+               rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
+               rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
+       }
        udelay(50);
 }
 
@@ -7902,7 +7905,8 @@ int cik_resume(struct radeon_device *rdev)
        /* init golden registers */
        cik_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = cik_startup(rdev);
index 1ecb3f1070e35c6ed3516e5f325eeeb61bc795b2..94626ea90fa57abc5efca249ab4d0d08cfc9566d 100644 (file)
@@ -264,6 +264,8 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev)
                WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
                WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0);
        }
+       rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false;
+       rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false;
 }
 
 /**
@@ -291,6 +293,11 @@ void cik_sdma_enable(struct radeon_device *rdev, bool enable)
        u32 me_cntl, reg_offset;
        int i;
 
+       if (enable == false) {
+               cik_sdma_gfx_stop(rdev);
+               cik_sdma_rlc_stop(rdev);
+       }
+
        for (i = 0; i < 2; i++) {
                if (i == 0)
                        reg_offset = SDMA0_REGISTER_OFFSET;
@@ -420,10 +427,6 @@ static int cik_sdma_load_microcode(struct radeon_device *rdev)
        if (!rdev->sdma_fw)
                return -EINVAL;
 
-       /* stop the gfx rings and rlc compute queues */
-       cik_sdma_gfx_stop(rdev);
-       cik_sdma_rlc_stop(rdev);
-
        /* halt the MEs */
        cik_sdma_enable(rdev, false);
 
@@ -492,9 +495,6 @@ int cik_sdma_resume(struct radeon_device *rdev)
  */
 void cik_sdma_fini(struct radeon_device *rdev)
 {
-       /* stop the gfx rings and rlc compute queues */
-       cik_sdma_gfx_stop(rdev);
-       cik_sdma_rlc_stop(rdev);
        /* halt the MEs */
        cik_sdma_enable(rdev, false);
        radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
index 713a5d35990102ea315fa078a93c11d6c1aae1f5..94e85875199481ca46e3c84cef453aaec3970356 100644 (file)
@@ -278,13 +278,15 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev)
        return !ASIC_IS_NODCE(rdev);
 }
 
-static void dce6_audio_enable(struct radeon_device *rdev,
-                             struct r600_audio_pin *pin,
-                             bool enable)
+void dce6_audio_enable(struct radeon_device *rdev,
+                      struct r600_audio_pin *pin,
+                      bool enable)
 {
+       if (!pin)
+               return;
+
        WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL,
-                       AUDIO_ENABLED);
-       DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
+                       enable ? AUDIO_ENABLED : 0);
 }
 
 static const u32 pin_offsets[7] =
@@ -323,7 +325,8 @@ int dce6_audio_init(struct radeon_device *rdev)
                rdev->audio.pin[i].connected = false;
                rdev->audio.pin[i].offset = pin_offsets[i];
                rdev->audio.pin[i].id = i;
-               dce6_audio_enable(rdev, &rdev->audio.pin[i], true);
+               /* disable audio.  it will be set up later */
+               dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
        }
 
        return 0;
index 5623e7542d99897142d49547f429940950f5c7c9..27b0ff16082ebbbe10eb385b8bce24e127b5091d 100644 (file)
@@ -5299,7 +5299,8 @@ int evergreen_resume(struct radeon_device *rdev)
        /* init golden registers */
        evergreen_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = evergreen_startup(rdev);
@@ -5475,9 +5476,9 @@ void evergreen_fini(struct radeon_device *rdev)
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
-       evergreen_pcie_gart_fini(rdev);
        uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
+       evergreen_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
        radeon_fence_driver_fini(rdev);
index 0c6d5cef4cf121770c63fcb559bf6cc187640292..05b0c95813fd79ff4c31ade3a90c0ad1880d028d 100644 (file)
@@ -306,6 +306,15 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
                return;
        offset = dig->afmt->offset;
 
+       /* disable audio prior to setting up hw */
+       if (ASIC_IS_DCE6(rdev)) {
+               dig->afmt->pin = dce6_audio_get_pin(rdev);
+               dce6_audio_enable(rdev, dig->afmt->pin, false);
+       } else {
+               dig->afmt->pin = r600_audio_get_pin(rdev);
+               r600_audio_enable(rdev, dig->afmt->pin, false);
+       }
+
        evergreen_audio_set_dto(encoder, mode->clock);
 
        WREG32(HDMI_VBI_PACKET_CONTROL + offset,
@@ -409,12 +418,16 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
        WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
        WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
        WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
+
+       /* enable audio after to setting up hw */
+       if (ASIC_IS_DCE6(rdev))
+               dce6_audio_enable(rdev, dig->afmt->pin, true);
+       else
+               r600_audio_enable(rdev, dig->afmt->pin, true);
 }
 
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
 {
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 
@@ -427,15 +440,6 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!enable && !dig->afmt->enabled)
                return;
 
-       if (enable) {
-               if (ASIC_IS_DCE6(rdev))
-                       dig->afmt->pin = dce6_audio_get_pin(rdev);
-               else
-                       dig->afmt->pin = r600_audio_get_pin(rdev);
-       } else {
-               dig->afmt->pin = NULL;
-       }
-
        dig->afmt->enabled = enable;
 
        DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
index 76ada8cfe902a4d9eaa9890404c390371f856621..3a03ba37d04346fb5200d67ee002716ae549a600 100644 (file)
@@ -57,7 +57,7 @@ typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;
 
 #define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100
 
-#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters   0x0
+#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters   0x8
 #define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable      0xC
 #define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20
 
index ea932ac66fc6647da43a8cf775b60ade25d478de..bf6300cfd62d0799deaefbd698027cf8d811dbc6 100644 (file)
@@ -2105,7 +2105,8 @@ int cayman_resume(struct radeon_device *rdev)
        /* init golden registers */
        ni_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = cayman_startup(rdev);
index ef024ce3f7ccfd39b1be47be9840a401b588b1dc..3cc78bb66042fc5509f26825560847374888288e 100644 (file)
@@ -3942,8 +3942,6 @@ int r100_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r100_startup(rdev);
        if (r) {
index 7c63ef840e86abaf04f216201b32ee2f40323b9b..0b658b34b33ab1d2874c0c85a668b4fa48da0ecc 100644 (file)
@@ -1430,8 +1430,6 @@ int r300_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r300_startup(rdev);
        if (r) {
index 3768aab2710b3943261312c4fcc5184b4f18a6fb..802b19220a21358712dc304a894db892ec3537fb 100644 (file)
@@ -325,8 +325,6 @@ int r420_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r420_startup(rdev);
        if (r) {
index e209eb75024f9dc1c441518cbe8f8d70a41844f5..98d6053c36c678aaf598e7a0b63193d00d042f5b 100644 (file)
@@ -240,8 +240,6 @@ int r520_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r520_startup(rdev);
        if (r) {
index cdbc4171fe73743bd9bcf9ce2bbb74020ad6ece5..647ef407921764692758c56e03f92b737202e317 100644 (file)
@@ -2968,7 +2968,8 @@ int r600_resume(struct radeon_device *rdev)
        /* post card */
        atom_asic_init(rdev->mode_info.atom_context);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = r600_startup(rdev);
index 47fc2b88697928b4272a0878927d189762a82000..bffac10c4296b3b4c28d9f7a52322fe51e9ae7c5 100644 (file)
@@ -142,12 +142,15 @@ void r600_audio_update_hdmi(struct work_struct *work)
 }
 
 /* enable the audio stream */
-static void r600_audio_enable(struct radeon_device *rdev,
-                             struct r600_audio_pin *pin,
-                             bool enable)
+void r600_audio_enable(struct radeon_device *rdev,
+                      struct r600_audio_pin *pin,
+                      bool enable)
 {
        u32 value = 0;
 
+       if (!pin)
+               return;
+
        if (ASIC_IS_DCE4(rdev)) {
                if (enable) {
                        value |= 0x81000000; /* Required to enable audio */
@@ -158,7 +161,6 @@ static void r600_audio_enable(struct radeon_device *rdev,
                WREG32_P(R600_AUDIO_ENABLE,
                         enable ? 0x81000000 : 0x0, ~0x81000000);
        }
-       DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
 }
 
 /*
@@ -178,8 +180,8 @@ int r600_audio_init(struct radeon_device *rdev)
        rdev->audio.pin[0].status_bits = 0;
        rdev->audio.pin[0].category_code = 0;
        rdev->audio.pin[0].id = 0;
-
-       r600_audio_enable(rdev, &rdev->audio.pin[0], true);
+       /* disable audio.  it will be set up later */
+       r600_audio_enable(rdev, &rdev->audio.pin[0], false);
 
        return 0;
 }
index 3016fc14f502c49a61c2343c3b2ca877d2590109..85a2bb28aed27699e464edc54a8573c8d1d41b39 100644 (file)
@@ -329,9 +329,6 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
        u8 *sadb;
        int sad_count;
 
-       /* XXX: setting this register causes hangs on some asics */
-       return;
-
        list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
                if (connector->encoder == encoder) {
                        radeon_connector = to_radeon_connector(connector);
@@ -460,6 +457,10 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
                return;
        offset = dig->afmt->offset;
 
+       /* disable audio prior to setting up hw */
+       dig->afmt->pin = r600_audio_get_pin(rdev);
+       r600_audio_enable(rdev, dig->afmt->pin, false);
+
        r600_audio_set_dto(encoder, mode->clock);
 
        WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
@@ -531,6 +532,9 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
        WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
 
        r600_hdmi_audio_workaround(encoder);
+
+       /* enable audio after to setting up hw */
+       r600_audio_enable(rdev, dig->afmt->pin, true);
 }
 
 /*
@@ -651,11 +655,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!enable && !dig->afmt->enabled)
                return;
 
-       if (enable)
-               dig->afmt->pin = r600_audio_get_pin(rdev);
-       else
-               dig->afmt->pin = NULL;
-
        /* Older chipsets require setting HDMI and routing manually */
        if (!ASIC_IS_DCE3(rdev)) {
                if (enable)
index 024db37b1832fdead3f64fbcecccff851493a633..e887d027b6d01fda8082305d11ff1b27bad06db9 100644 (file)
@@ -2747,6 +2747,12 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
 void r600_audio_update_hdmi(struct work_struct *work);
 struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev);
 struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev);
+void r600_audio_enable(struct radeon_device *rdev,
+                      struct r600_audio_pin *pin,
+                      bool enable);
+void dce6_audio_enable(struct radeon_device *rdev,
+                      struct r600_audio_pin *pin,
+                      bool enable);
 
 /*
  * R600 vram scratch functions
index 485848f889f55c9f4b86bf61bd8c019e2ad96a27..fa9a9c02751ea865251f7854665c3757caa48e00 100644 (file)
@@ -219,7 +219,8 @@ static int radeon_atpx_verify_interface(struct radeon_atpx *atpx)
        memcpy(&output, info->buffer.pointer, size);
 
        /* TODO: check version? */
-       printk("ATPX version %u\n", output.version);
+       printk("ATPX version %u, functions 0x%08x\n",
+              output.version, output.function_bits);
 
        radeon_atpx_parse_functions(&atpx->functions, output.function_bits);
 
index b012cbbc3ed5a9b892b433eff0ee5f3134a130de..044bc98fb459e46fac62b929696ad047f835360d 100644 (file)
@@ -1521,13 +1521,16 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        if (r)
                DRM_ERROR("ib ring test failed (%d).\n", r);
 
-       if (rdev->pm.dpm_enabled) {
+       if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
                /* do dpm late init */
                r = radeon_pm_late_init(rdev);
                if (r) {
                        rdev->pm.dpm_enabled = false;
                        DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
                }
+       } else {
+               /* resume old pm late */
+               radeon_pm_resume(rdev);
        }
 
        radeon_restore_bios_scratch_regs(rdev);
index 114d1672d616d0b5d7b85ab5d739da66f2db823e..66ed3ea7144010e7c95bc0d07c01ad5499242947 100644 (file)
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+
+#if defined(CONFIG_VGA_SWITCHEROO)
+bool radeon_is_px(void);
+#else
+static inline bool radeon_is_px(void) { return false; }
+#endif
+
 /**
  * radeon_driver_unload_kms - Main unload function for KMS.
  *
@@ -130,7 +137,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
                                "Error during ACPI methods call\n");
        }
 
-       if (radeon_runtime_pm != 0) {
+       if ((radeon_runtime_pm == 1) ||
+           ((radeon_runtime_pm == -1) && radeon_is_px())) {
                pm_runtime_use_autosuspend(dev->dev);
                pm_runtime_set_autosuspend_delay(dev->dev, 5000);
                pm_runtime_set_active(dev->dev);
@@ -537,6 +545,10 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
 
                radeon_vm_init(rdev, &fpriv->vm);
 
+               r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
+               if (r)
+                       return r;
+
                /* map the ib pool buffer read only into
                 * virtual address space */
                bo_va = radeon_vm_bo_add(rdev, &fpriv->vm,
@@ -544,6 +556,8 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
                r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET,
                                          RADEON_VM_PAGE_READABLE |
                                          RADEON_VM_PAGE_SNOOPED);
+
+               radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
                if (r) {
                        radeon_vm_fini(rdev, &fpriv->vm);
                        kfree(fpriv);
index 77f5b0c3edb8d8b1f4835620d626c3981171c7a6..040a2a10ea17e8136a4274decc83de131ad79e3f 100644 (file)
@@ -714,6 +714,9 @@ int radeon_ttm_init(struct radeon_device *rdev)
                DRM_ERROR("Failed initializing VRAM heap.\n");
                return r;
        }
+       /* Change the size here instead of the init above so only lpfn is affected */
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+
        r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true,
                             RADEON_GEM_DOMAIN_VRAM,
                             NULL, &rdev->stollen_vga_memory);
@@ -935,7 +938,7 @@ static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf,
        while (size) {
                loff_t p = *pos / PAGE_SIZE;
                unsigned off = *pos & ~PAGE_MASK;
-               ssize_t cur_size = min(size, PAGE_SIZE - off);
+               size_t cur_size = min_t(size_t, size, PAGE_SIZE - off);
                struct page *page;
                void *ptr;
 
index 6781fee1eaadc21a68e50de696dd353be0a3e9e5..3e6804b2b2ef748e9727e34817243aa31e7f9210 100644 (file)
@@ -171,6 +171,8 @@ void radeon_uvd_fini(struct radeon_device *rdev)
 
        radeon_bo_unref(&rdev->uvd.vcpu_bo);
 
+       radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]);
+
        release_firmware(rdev->uvd_fw);
 }
 
index b5c2369cda2fe28ca043fe91f4fcfe12fc227fc6..130d5cc50d436fd90c1d3055bd03e177ba2dce6c 100644 (file)
@@ -474,8 +474,6 @@ int rs400_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = rs400_startup(rdev);
        if (r) {
index fdcde7693032c28cc30008b494fd573fd82e58f3..72d3616de08e054efe6199fcd529f59cef3e18d5 100644 (file)
@@ -1048,8 +1048,6 @@ int rs600_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = rs600_startup(rdev);
        if (r) {
index 35950738bd5e449465e0e5062d096e3e8ae9ff0e..3462b64369bfe6142a4c8acfaec09e0bb7d8826c 100644 (file)
@@ -756,8 +756,6 @@ int rs690_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = rs690_startup(rdev);
        if (r) {
index 98e8138ff77945ecdba447bdcb94310c30dcb1c7..237dd29d9f1c893b1e17600fec59660848b394c3 100644 (file)
@@ -586,8 +586,6 @@ int rv515_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r =  rv515_startup(rdev);
        if (r) {
index 6c772e58c7845e7d4170287d3e583afd64c5a3e8..fef310773aadc71260888372b896df0afcced749 100644 (file)
@@ -1811,7 +1811,8 @@ int rv770_resume(struct radeon_device *rdev)
        /* init golden registers */
        rv770_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = rv770_startup(rdev);
@@ -1955,9 +1956,9 @@ void rv770_fini(struct radeon_device *rdev)
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
-       rv770_pcie_gart_fini(rdev);
        uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
+       rv770_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
        radeon_fence_driver_fini(rdev);
index 83578324e5d1383167f75071cdaf47d85a0e60ea..9a124d0608b36f3ae594709ac92c4d4ad563b6d7 100644 (file)
@@ -6618,7 +6618,8 @@ int si_resume(struct radeon_device *rdev)
        /* init golden registers */
        si_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = si_startup(rdev);
index 88a529008ce0e59210e917422b2cfe07570a0d7d..c71594754f46fa18810d5b654d2c2d31288f6c3a 100644 (file)
@@ -104,7 +104,7 @@ static void tegra_drm_context_free(struct tegra_drm_context *context)
 
 static void tegra_drm_lastclose(struct drm_device *drm)
 {
-#ifdef CONFIG_TEGRA_DRM_FBDEV
+#ifdef CONFIG_DRM_TEGRA_FBDEV
        struct tegra_drm *tegra = drm->dev_private;
 
        tegra_fbdev_restore_mode(tegra->fbdev);
index 338f7f6561d701d601a92b2f6362782536d03e2e..0266fb40479eae05f5176e9835d7c2a1ede75519 100644 (file)
@@ -15,6 +15,7 @@
 struct tegra_rgb {
        struct tegra_output output;
        struct tegra_dc *dc;
+       bool enabled;
 
        struct clk *clk_parent;
        struct clk *clk;
@@ -89,6 +90,9 @@ static int tegra_output_rgb_enable(struct tegra_output *output)
        struct tegra_rgb *rgb = to_rgb(output);
        unsigned long value;
 
+       if (rgb->enabled)
+               return 0;
+
        tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
 
        value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
@@ -122,6 +126,8 @@ static int tegra_output_rgb_enable(struct tegra_output *output)
        tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
        tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
 
+       rgb->enabled = true;
+
        return 0;
 }
 
@@ -130,6 +136,9 @@ static int tegra_output_rgb_disable(struct tegra_output *output)
        struct tegra_rgb *rgb = to_rgb(output);
        unsigned long value;
 
+       if (!rgb->enabled)
+               return 0;
+
        value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
        value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
                   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
@@ -144,6 +153,8 @@ static int tegra_output_rgb_disable(struct tegra_output *output)
 
        tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
 
+       rgb->enabled = false;
+
        return 0;
 }
 
index a066513093880a218d185624589ec07efce66b0b..214b7992a3aa74296eeb2a083b28398c08c3cb4d 100644 (file)
@@ -351,9 +351,11 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
 
 moved:
        if (bo->evicted) {
-               ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
-               if (ret)
-                       pr_err("Can not flush read caches\n");
+               if (bdev->driver->invalidate_caches) {
+                       ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
+                       if (ret)
+                               pr_err("Can not flush read caches\n");
+               }
                bo->evicted = false;
        }
 
index 801231c9ae483980afe0e93a0af73a7f07123864..0ce48e5a9cb4a70b56461f0ceb529e2c48ed58aa 100644 (file)
@@ -339,11 +339,13 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
        vma->vm_private_data = bo;
 
        /*
-        * PFNMAP is faster than MIXEDMAP due to reduced page
-        * administration. So use MIXEDMAP only if private VMA, where
-        * we need to support COW.
+        * We'd like to use VM_PFNMAP on shared mappings, where
+        * (vma->vm_flags & VM_SHARED) != 0, for performance reasons,
+        * but for some reason VM_PFNMAP + x86 PAT + write-combine is very
+        * bad for performance. Until that has been sorted out, use
+        * VM_MIXEDMAP on all mappings. See freedesktop.org bug #75719
         */
-       vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+       vma->vm_flags |= VM_MIXEDMAP;
        vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
        return 0;
 out_unref:
@@ -359,7 +361,7 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
 
        vma->vm_ops = &ttm_bo_vm_ops;
        vma->vm_private_data = ttm_bo_reference(bo);
-       vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+       vma->vm_flags |= VM_MIXEDMAP;
        vma->vm_flags |= VM_IO | VM_DONTEXPAND;
        return 0;
 }
index bb594c11605e6fca6dc2d84e0b3017d5b6587d55..f58dc7dd15c576ad2e4e0a702ee6aea1bffb01ce 100644 (file)
@@ -261,12 +261,7 @@ typedef enum SVGA3dSurfaceFormat {
    /* Planar video formats. */
    SVGA3D_YV12                         = 121,
 
-   /* Shader constant formats. */
-   SVGA3D_SURFACE_SHADERCONST_FLOAT    = 122,
-   SVGA3D_SURFACE_SHADERCONST_INT      = 123,
-   SVGA3D_SURFACE_SHADERCONST_BOOL     = 124,
-
-   SVGA3D_FORMAT_MAX                   = 125,
+   SVGA3D_FORMAT_MAX                   = 122,
 } SVGA3dSurfaceFormat;
 
 typedef uint32 SVGA3dColor; /* a, r, g, b */
index 9e4be1725985906f65ed22be6bc90968e9fe8523..07831554dad7acc3dae34f36e3a96e7b7f5299af 100644 (file)
@@ -40,7 +40,7 @@
 #include <drm/ttm/ttm_module.h>
 #include "vmwgfx_fence.h"
 
-#define VMWGFX_DRIVER_DATE "20121114"
+#define VMWGFX_DRIVER_DATE "20140228"
 #define VMWGFX_DRIVER_MAJOR 2
 #define VMWGFX_DRIVER_MINOR 5
 #define VMWGFX_DRIVER_PATCHLEVEL 0
index d4a5a19cb8c3ca1bd9db9424aad745ecfea5f868..04a64b8cd3cd4f17e00765efe2769e502c4b8240 100644 (file)
@@ -188,18 +188,20 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv,
 
        bo = otable->page_table->pt_bo;
        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
-       if (unlikely(cmd == NULL))
-               DRM_ERROR("Failed reserving FIFO space for OTable setup.\n");
-
-       memset(cmd, 0, sizeof(*cmd));
-       cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
-       cmd->header.size = sizeof(cmd->body);
-       cmd->body.type = type;
-       cmd->body.baseAddress = 0;
-       cmd->body.sizeInBytes = 0;
-       cmd->body.validSizeInBytes = 0;
-       cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
-       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for OTable "
+                         "takedown.\n");
+       } else {
+               memset(cmd, 0, sizeof(*cmd));
+               cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
+               cmd->header.size = sizeof(cmd->body);
+               cmd->body.type = type;
+               cmd->body.baseAddress = 0;
+               cmd->body.sizeInBytes = 0;
+               cmd->body.validSizeInBytes = 0;
+               cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
+               vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       }
 
        if (bo) {
                int ret;
@@ -562,11 +564,12 @@ void vmw_mob_unbind(struct vmw_private *dev_priv,
        if (unlikely(cmd == NULL)) {
                DRM_ERROR("Failed reserving FIFO space for Memory "
                          "Object unbinding.\n");
+       } else {
+               cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
+               cmd->header.size = sizeof(cmd->body);
+               cmd->body.mobid = mob->id;
+               vmw_fifo_commit(dev_priv, sizeof(*cmd));
        }
-       cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
-       cmd->header.size = sizeof(cmd->body);
-       cmd->body.mobid = mob->id;
-       vmw_fifo_commit(dev_priv, sizeof(*cmd));
        if (bo) {
                vmw_fence_single_bo(bo, NULL);
                ttm_bo_unreserve(bo);
index 2aa4bc6a4d601578c294c3003b15985de9b28385..9757b57f8388d7a29fa51d04f61f5076fd149793 100644 (file)
@@ -427,8 +427,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
        INIT_LIST_HEAD(&vmw_bo->res_list);
 
        ret = ttm_bo_init(bdev, &vmw_bo->base, size,
-                         (user) ? ttm_bo_type_device :
-                         ttm_bo_type_kernel, placement,
+                         ttm_bo_type_device, placement,
                          0, interruptible,
                          NULL, acc_size, NULL, bo_free);
        return ret;
index 82468d9029156c6588a4480a9c0ed8c0aed82736..e7af580ab977f5932629b8d45e5d5e68a52942a5 100644 (file)
@@ -830,6 +830,24 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
        if (unlikely(ret != 0))
                goto out_unlock;
 
+       /*
+        * A gb-aware client referencing a shared surface will
+        * expect a backup buffer to be present.
+        */
+       if (dev_priv->has_mob && req->shareable) {
+               uint32_t backup_handle;
+
+               ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
+                                           res->backup_size,
+                                           true,
+                                           &backup_handle,
+                                           &res->backup);
+               if (unlikely(ret != 0)) {
+                       vmw_resource_unreference(&res);
+                       goto out_unlock;
+               }
+       }
+
        tmp = vmw_resource_reference(&srf->res);
        ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
                                    req->shareable, VMW_RES_SURFACE,
index 1146e3bba6e19bb69cd7f866c149b4aa7202ae46..112f27e51bc7df81b45efcb58f7c11fc46f097e0 100644 (file)
@@ -538,7 +538,7 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
 
                g->base = job->gather_addr_phys[i];
 
-               for (j = 0; j < job->num_gathers; j++)
+               for (j = i + 1; j < job->num_gathers; j++)
                        if (job->gathers[j].bo == g->bo)
                                job->gathers[j].handled = true;
 
index a7626358c95df29c2ccb62fa89ed23251acfb979..029b65e6c58914d36061914e35738bda0c1e385c 100644 (file)
@@ -243,7 +243,7 @@ static ssize_t set_temp_min(struct device *dev,
        data->temp_min[index] = clamp_val(temp/1000, -128, 127);
        if (i2c_smbus_write_byte_data(client,
                                        MAX1668_REG_LIML_WR(index),
-                                       data->temp_max[index]))
+                                       data->temp_min[index]))
                count = -EIO;
        mutex_unlock(&data->update_lock);
 
index f5ed03164d86c314942453d244f103d6e9276070..de17c5593d97c1d702563217f0932aa0a0aee6bd 100644 (file)
@@ -387,7 +387,7 @@ config I2C_CBUS_GPIO
 
 config I2C_CPM
        tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
-       depends on (CPM1 || CPM2) && OF_I2C
+       depends on CPM1 || CPM2
        help
          This supports the use of the I2C interface on Freescale
          processors with CPM1 or CPM2.
index 41c64a43bcab163a1b08d70ce1433ee1e941b86a..ac2d69e34c8ceb60661c5f3b433d415939e607f9 100644 (file)
@@ -70,7 +70,7 @@ config IIO_ST_GYRO_3AXIS
        select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
        help
          Say yes here to build support for STMicroelectronics gyroscopes:
-         L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330.
+         L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330.
 
          This driver can also be built as a module. If so, these modules
          will be created:
index f8f2bf84a5a281f9d9cff04eeb4af3d81de6c5be..c197360c450bd8549a980a24941b322df4fca88f 100644 (file)
@@ -19,7 +19,6 @@
 #define LSM330DL_GYRO_DEV_NAME         "lsm330dl_gyro"
 #define LSM330DLC_GYRO_DEV_NAME                "lsm330dlc_gyro"
 #define L3GD20_GYRO_DEV_NAME           "l3gd20"
-#define L3GD20H_GYRO_DEV_NAME          "l3gd20h"
 #define L3G4IS_GYRO_DEV_NAME           "l3g4is_ui"
 #define LSM330_GYRO_DEV_NAME           "lsm330_gyro"
 
index d53d91adfb557b0e575a17030221c6e01b2b7d38..a8e174a47bc409cc22ece45c5a971ca3fe14f37d 100644 (file)
@@ -167,11 +167,10 @@ static const struct st_sensors st_gyro_sensors[] = {
                .wai = ST_GYRO_2_WAI_EXP,
                .sensors_supported = {
                        [0] = L3GD20_GYRO_DEV_NAME,
-                       [1] = L3GD20H_GYRO_DEV_NAME,
-                       [2] = LSM330D_GYRO_DEV_NAME,
-                       [3] = LSM330DLC_GYRO_DEV_NAME,
-                       [4] = L3G4IS_GYRO_DEV_NAME,
-                       [5] = LSM330_GYRO_DEV_NAME,
+                       [1] = LSM330D_GYRO_DEV_NAME,
+                       [2] = LSM330DLC_GYRO_DEV_NAME,
+                       [3] = L3G4IS_GYRO_DEV_NAME,
+                       [4] = LSM330_GYRO_DEV_NAME,
                },
                .ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
                .odr = {
index 16b8b8d70bf127973b43f819999c3876f7a8683d..23c12f361b05b13f37430df0958f02a406b8812d 100644 (file)
@@ -55,7 +55,6 @@ static const struct i2c_device_id st_gyro_id_table[] = {
        { LSM330DL_GYRO_DEV_NAME },
        { LSM330DLC_GYRO_DEV_NAME },
        { L3GD20_GYRO_DEV_NAME },
-       { L3GD20H_GYRO_DEV_NAME },
        { L3G4IS_GYRO_DEV_NAME },
        { LSM330_GYRO_DEV_NAME },
        {},
index 94763e25caf999c22f2237fa3a5783d063512173..b4ad3be2668768e7a4ef35979478ed033933007f 100644 (file)
@@ -54,7 +54,6 @@ static const struct spi_device_id st_gyro_id_table[] = {
        { LSM330DL_GYRO_DEV_NAME },
        { LSM330DLC_GYRO_DEV_NAME },
        { L3GD20_GYRO_DEV_NAME },
-       { L3GD20H_GYRO_DEV_NAME },
        { L3G4IS_GYRO_DEV_NAME },
        { LSM330_GYRO_DEV_NAME },
        {},
index f17b4e6183c6bae6f36ee8acfaac897f76dfd8d9..47a6dbac2d0ca8b23dcea31158b43d3c3df3d2f0 100644 (file)
@@ -103,13 +103,13 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
 /**
  *  cm32181_read_als_it() - Get sensor integration time (ms)
  *  @cm32181:  pointer of struct cm32181
- *  @val     pointer of int to load the als_it value.
+ *  @val2:     pointer of int to load the als_it value.
  *
  *  Report the current integartion time by millisecond.
  *
- *  Return: IIO_VAL_INT for success, otherwise -EINVAL.
+ *  Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
  */
-static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val)
+static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
 {
        u16 als_it;
        int i;
@@ -119,8 +119,8 @@ static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val)
        als_it >>= CM32181_CMD_ALS_IT_SHIFT;
        for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
                if (als_it == als_it_bits[i]) {
-                       *val = als_it_value[i];
-                       return IIO_VAL_INT;
+                       *val2 = als_it_value[i];
+                       return IIO_VAL_INT_PLUS_MICRO;
                }
        }
 
@@ -221,7 +221,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
                *val = cm32181->calibscale;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_INT_TIME:
-               ret = cm32181_read_als_it(cm32181, val);
+               ret = cm32181_read_als_it(cm32181, val2);
                return ret;
        }
 
@@ -240,7 +240,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
                cm32181->calibscale = val;
                return val;
        case IIO_CHAN_INFO_INT_TIME:
-               ret = cm32181_write_als_it(cm32181, val);
+               ret = cm32181_write_als_it(cm32181, val2);
                return ret;
        }
 
@@ -264,7 +264,7 @@ static ssize_t cm32181_get_it_available(struct device *dev,
 
        n = ARRAY_SIZE(als_it_value);
        for (i = 0, len = 0; i < n; i++)
-               len += sprintf(buf + len, "%d ", als_it_value[i]);
+               len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
        return len + sprintf(buf + len, "\n");
 }
 
index 0a142af83e25dbb112809f04a048fd581f9a7d96..a45e07492db318a22171546291d2b590e0d0668f 100644 (file)
 #define CM36651_CS_CONF2_DEFAULT_BIT   0x08
 
 /* CS_CONF3 channel integration time */
-#define CM36651_CS_IT1                 0x00 /* Integration time 80000 usec */
-#define CM36651_CS_IT2                 0x40 /* Integration time 160000 usec */
-#define CM36651_CS_IT3                 0x80 /* Integration time 320000 usec */
-#define CM36651_CS_IT4                 0xC0 /* Integration time 640000 usec */
+#define CM36651_CS_IT1                 0x00 /* Integration time 80 msec */
+#define CM36651_CS_IT2                 0x40 /* Integration time 160 msec */
+#define CM36651_CS_IT3                 0x80 /* Integration time 320 msec */
+#define CM36651_CS_IT4                 0xC0 /* Integration time 640 msec */
 
 /* PS_CONF1 command code */
 #define CM36651_PS_ENABLE              0x00
 #define CM36651_PS_PERS4               0x0C
 
 /* PS_CONF1 command code: integration time */
-#define CM36651_PS_IT1                 0x00 /* Integration time 320 usec */
-#define CM36651_PS_IT2                 0x10 /* Integration time 420 usec */
-#define CM36651_PS_IT3                 0x20 /* Integration time 520 usec */
-#define CM36651_PS_IT4                 0x30 /* Integration time 640 usec */
+#define CM36651_PS_IT1                 0x00 /* Integration time 0.32 msec */
+#define CM36651_PS_IT2                 0x10 /* Integration time 0.42 msec */
+#define CM36651_PS_IT3                 0x20 /* Integration time 0.52 msec */
+#define CM36651_PS_IT4                 0x30 /* Integration time 0.64 msec */
 
 /* PS_CONF1 command code: duty ratio */
 #define CM36651_PS_DR1                 0x00 /* Duty ratio 1/80 */
@@ -93,8 +93,8 @@
 #define CM36651_CLOSE_PROXIMITY                0x32
 #define CM36651_FAR_PROXIMITY                  0x33
 
-#define CM36651_CS_INT_TIME_AVAIL      "80000 160000 320000 640000"
-#define CM36651_PS_INT_TIME_AVAIL      "320 420 520 640"
+#define CM36651_CS_INT_TIME_AVAIL      "0.08 0.16 0.32 0.64"
+#define CM36651_PS_INT_TIME_AVAIL      "0.000320 0.000420 0.000520 0.000640"
 
 enum cm36651_operation_mode {
        CM36651_LIGHT_EN,
@@ -356,30 +356,30 @@ static int cm36651_read_channel(struct cm36651_data *cm36651,
 }
 
 static int cm36651_read_int_time(struct cm36651_data *cm36651,
-                               struct iio_chan_spec const *chan, int *val)
+                               struct iio_chan_spec const *chan, int *val2)
 {
        switch (chan->type) {
        case IIO_LIGHT:
                if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT1)
-                       *val = 80000;
+                       *val2 = 80000;
                else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT2)
-                       *val = 160000;
+                       *val2 = 160000;
                else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT3)
-                       *val = 320000;
+                       *val2 = 320000;
                else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT4)
-                       *val = 640000;
+                       *val2 = 640000;
                else
                        return -EINVAL;
                break;
        case IIO_PROXIMITY:
                if (cm36651->ps_int_time == CM36651_PS_IT1)
-                       *val = 320;
+                       *val2 = 320;
                else if (cm36651->ps_int_time == CM36651_PS_IT2)
-                       *val = 420;
+                       *val2 = 420;
                else if (cm36651->ps_int_time == CM36651_PS_IT3)
-                       *val = 520;
+                       *val2 = 520;
                else if (cm36651->ps_int_time == CM36651_PS_IT4)
-                       *val = 640;
+                       *val2 = 640;
                else
                        return -EINVAL;
                break;
@@ -387,7 +387,7 @@ static int cm36651_read_int_time(struct cm36651_data *cm36651,
                return -EINVAL;
        }
 
-       return IIO_VAL_INT;
+       return IIO_VAL_INT_PLUS_MICRO;
 }
 
 static int cm36651_write_int_time(struct cm36651_data *cm36651,
@@ -459,7 +459,8 @@ static int cm36651_read_raw(struct iio_dev *indio_dev,
                ret = cm36651_read_channel(cm36651, chan, val);
                break;
        case IIO_CHAN_INFO_INT_TIME:
-               ret = cm36651_read_int_time(cm36651, chan, val);
+               *val = 0;
+               ret = cm36651_read_int_time(cm36651, chan, val2);
                break;
        default:
                ret = -EINVAL;
@@ -479,7 +480,7 @@ static int cm36651_write_raw(struct iio_dev *indio_dev,
        int ret = -EINVAL;
 
        if (mask == IIO_CHAN_INFO_INT_TIME) {
-               ret = cm36651_write_int_time(cm36651, chan, val);
+               ret = cm36651_write_int_time(cm36651, chan, val2);
                if (ret < 0)
                        dev_err(&client->dev, "Integration time write failed\n");
        }
index d286bdebe2ab90fc613c7696d41690909247da52..7e98a58aacfd68f6d8af350b2483e225409df55c 100644 (file)
@@ -1647,6 +1647,15 @@ static inline int act_open_has_tid(int status)
               status != CPL_ERR_ARP_MISS;
 }
 
+/* Returns whether a CPL status conveys negative advice.
+ */
+static int is_neg_adv(unsigned int status)
+{
+       return status == CPL_ERR_RTX_NEG_ADVICE ||
+              status == CPL_ERR_PERSIST_NEG_ADVICE ||
+              status == CPL_ERR_KEEPALV_NEG_ADVICE;
+}
+
 #define ACT_OPEN_RETRY_COUNT 2
 
 static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
@@ -1835,7 +1844,7 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid,
             status, status2errno(status));
 
-       if (status == CPL_ERR_RTX_NEG_ADVICE) {
+       if (is_neg_adv(status)) {
                printk(KERN_WARNING MOD "Connection problems for atid %u\n",
                        atid);
                return 0;
@@ -2265,15 +2274,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
        return 0;
 }
 
-/*
- * Returns whether an ABORT_REQ_RSS message is a negative advice.
- */
-static int is_neg_adv_abort(unsigned int status)
-{
-       return status == CPL_ERR_RTX_NEG_ADVICE ||
-              status == CPL_ERR_PERSIST_NEG_ADVICE;
-}
-
 static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
 {
        struct cpl_abort_req_rss *req = cplhdr(skb);
@@ -2287,7 +2287,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
        unsigned int tid = GET_TID(req);
 
        ep = lookup_tid(t, tid);
-       if (is_neg_adv_abort(req->status)) {
+       if (is_neg_adv(req->status)) {
                PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
                     ep->hwtid);
                return 0;
@@ -3570,7 +3570,7 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
                kfree_skb(skb);
                return 0;
        }
-       if (is_neg_adv_abort(req->status)) {
+       if (is_neg_adv(req->status)) {
                PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
                     ep->hwtid);
                kfree_skb(skb);
index 4a033853312e52c6ff026d8e7e7892f010826255..ba7335fd4ebfca7db505585ac7fbee792fd4d67e 100644 (file)
@@ -64,6 +64,10 @@ struct uld_ctx {
 static LIST_HEAD(uld_ctx_list);
 static DEFINE_MUTEX(dev_mutex);
 
+#define DB_FC_RESUME_SIZE 64
+#define DB_FC_RESUME_DELAY 1
+#define DB_FC_DRAIN_THRESH 0
+
 static struct dentry *c4iw_debugfs_root;
 
 struct c4iw_debugfs_data {
@@ -282,7 +286,7 @@ static const struct file_operations stag_debugfs_fops = {
        .llseek  = default_llseek,
 };
 
-static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY"};
+static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY", "STOPPED"};
 
 static int stats_show(struct seq_file *seq, void *v)
 {
@@ -311,9 +315,10 @@ static int stats_show(struct seq_file *seq, void *v)
        seq_printf(seq, "  DB FULL: %10llu\n", dev->rdev.stats.db_full);
        seq_printf(seq, " DB EMPTY: %10llu\n", dev->rdev.stats.db_empty);
        seq_printf(seq, "  DB DROP: %10llu\n", dev->rdev.stats.db_drop);
-       seq_printf(seq, " DB State: %s Transitions %llu\n",
+       seq_printf(seq, " DB State: %s Transitions %llu FC Interruptions %llu\n",
                   db_state_str[dev->db_state],
-                  dev->rdev.stats.db_state_transitions);
+                  dev->rdev.stats.db_state_transitions,
+                  dev->rdev.stats.db_fc_interruptions);
        seq_printf(seq, "TCAM_FULL: %10llu\n", dev->rdev.stats.tcam_full);
        seq_printf(seq, "ACT_OFLD_CONN_FAILS: %10llu\n",
                   dev->rdev.stats.act_ofld_conn_fails);
@@ -643,6 +648,12 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
                printk(KERN_ERR MOD "error %d initializing ocqp pool\n", err);
                goto err4;
        }
+       rdev->status_page = (struct t4_dev_status_page *)
+                           __get_free_page(GFP_KERNEL);
+       if (!rdev->status_page) {
+               pr_err(MOD "error allocating status page\n");
+               goto err4;
+       }
        return 0;
 err4:
        c4iw_rqtpool_destroy(rdev);
@@ -656,6 +667,7 @@ err1:
 
 static void c4iw_rdev_close(struct c4iw_rdev *rdev)
 {
+       free_page((unsigned long)rdev->status_page);
        c4iw_pblpool_destroy(rdev);
        c4iw_rqtpool_destroy(rdev);
        c4iw_destroy_resource(&rdev->resource);
@@ -703,18 +715,6 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
                pr_info("%s: On-Chip Queues not supported on this device.\n",
                        pci_name(infop->pdev));
 
-       if (!is_t4(infop->adapter_type)) {
-               if (!allow_db_fc_on_t5) {
-                       db_fc_threshold = 100000;
-                       pr_info("DB Flow Control Disabled.\n");
-               }
-
-               if (!allow_db_coalescing_on_t5) {
-                       db_coalescing_threshold = -1;
-                       pr_info("DB Coalescing Disabled.\n");
-               }
-       }
-
        devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp));
        if (!devp) {
                printk(KERN_ERR MOD "Cannot allocate ib device\n");
@@ -749,6 +749,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
        spin_lock_init(&devp->lock);
        mutex_init(&devp->rdev.stats.lock);
        mutex_init(&devp->db_mutex);
+       INIT_LIST_HEAD(&devp->db_fc_list);
 
        if (c4iw_debugfs_root) {
                devp->debugfs_root = debugfs_create_dir(
@@ -977,13 +978,16 @@ static int disable_qp_db(int id, void *p, void *data)
 
 static void stop_queues(struct uld_ctx *ctx)
 {
-       spin_lock_irq(&ctx->dev->lock);
-       if (ctx->dev->db_state == NORMAL) {
-               ctx->dev->rdev.stats.db_state_transitions++;
-               ctx->dev->db_state = FLOW_CONTROL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->dev->lock, flags);
+       ctx->dev->rdev.stats.db_state_transitions++;
+       ctx->dev->db_state = STOPPED;
+       if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED)
                idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
-       }
-       spin_unlock_irq(&ctx->dev->lock);
+       else
+               ctx->dev->rdev.status_page->db_off = 1;
+       spin_unlock_irqrestore(&ctx->dev->lock, flags);
 }
 
 static int enable_qp_db(int id, void *p, void *data)
@@ -994,15 +998,70 @@ static int enable_qp_db(int id, void *p, void *data)
        return 0;
 }
 
+static void resume_rc_qp(struct c4iw_qp *qp)
+{
+       spin_lock(&qp->lock);
+       t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc);
+       qp->wq.sq.wq_pidx_inc = 0;
+       t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc);
+       qp->wq.rq.wq_pidx_inc = 0;
+       spin_unlock(&qp->lock);
+}
+
+static void resume_a_chunk(struct uld_ctx *ctx)
+{
+       int i;
+       struct c4iw_qp *qp;
+
+       for (i = 0; i < DB_FC_RESUME_SIZE; i++) {
+               qp = list_first_entry(&ctx->dev->db_fc_list, struct c4iw_qp,
+                                     db_fc_entry);
+               list_del_init(&qp->db_fc_entry);
+               resume_rc_qp(qp);
+               if (list_empty(&ctx->dev->db_fc_list))
+                       break;
+       }
+}
+
 static void resume_queues(struct uld_ctx *ctx)
 {
        spin_lock_irq(&ctx->dev->lock);
-       if (ctx->dev->qpcnt <= db_fc_threshold &&
-           ctx->dev->db_state == FLOW_CONTROL) {
-               ctx->dev->db_state = NORMAL;
-               ctx->dev->rdev.stats.db_state_transitions++;
-               idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
+       if (ctx->dev->db_state != STOPPED)
+               goto out;
+       ctx->dev->db_state = FLOW_CONTROL;
+       while (1) {
+               if (list_empty(&ctx->dev->db_fc_list)) {
+                       WARN_ON(ctx->dev->db_state != FLOW_CONTROL);
+                       ctx->dev->db_state = NORMAL;
+                       ctx->dev->rdev.stats.db_state_transitions++;
+                       if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED) {
+                               idr_for_each(&ctx->dev->qpidr, enable_qp_db,
+                                            NULL);
+                       } else {
+                               ctx->dev->rdev.status_page->db_off = 0;
+                       }
+                       break;
+               } else {
+                       if (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1)
+                           < (ctx->dev->rdev.lldi.dbfifo_int_thresh <<
+                              DB_FC_DRAIN_THRESH)) {
+                               resume_a_chunk(ctx);
+                       }
+                       if (!list_empty(&ctx->dev->db_fc_list)) {
+                               spin_unlock_irq(&ctx->dev->lock);
+                               if (DB_FC_RESUME_DELAY) {
+                                       set_current_state(TASK_UNINTERRUPTIBLE);
+                                       schedule_timeout(DB_FC_RESUME_DELAY);
+                               }
+                               spin_lock_irq(&ctx->dev->lock);
+                               if (ctx->dev->db_state != FLOW_CONTROL)
+                                       break;
+                       }
+               }
        }
+out:
+       if (ctx->dev->db_state != NORMAL)
+               ctx->dev->rdev.stats.db_fc_interruptions++;
        spin_unlock_irq(&ctx->dev->lock);
 }
 
@@ -1028,12 +1087,12 @@ static int count_qps(int id, void *p, void *data)
        return 0;
 }
 
-static void deref_qps(struct qp_list qp_list)
+static void deref_qps(struct qp_list *qp_list)
 {
        int idx;
 
-       for (idx = 0; idx < qp_list.idx; idx++)
-               c4iw_qp_rem_ref(&qp_list.qps[idx]->ibqp);
+       for (idx = 0; idx < qp_list->idx; idx++)
+               c4iw_qp_rem_ref(&qp_list->qps[idx]->ibqp);
 }
 
 static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
@@ -1044,17 +1103,22 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
        for (idx = 0; idx < qp_list->idx; idx++) {
                struct c4iw_qp *qp = qp_list->qps[idx];
 
+               spin_lock_irq(&qp->rhp->lock);
+               spin_lock(&qp->lock);
                ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
                                          qp->wq.sq.qid,
                                          t4_sq_host_wq_pidx(&qp->wq),
                                          t4_sq_wq_size(&qp->wq));
                if (ret) {
-                       printk(KERN_ERR MOD "%s: Fatal error - "
+                       pr_err(KERN_ERR MOD "%s: Fatal error - "
                               "DB overflow recovery failed - "
                               "error syncing SQ qid %u\n",
                               pci_name(ctx->lldi.pdev), qp->wq.sq.qid);
+                       spin_unlock(&qp->lock);
+                       spin_unlock_irq(&qp->rhp->lock);
                        return;
                }
+               qp->wq.sq.wq_pidx_inc = 0;
 
                ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
                                          qp->wq.rq.qid,
@@ -1062,12 +1126,17 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
                                          t4_rq_wq_size(&qp->wq));
 
                if (ret) {
-                       printk(KERN_ERR MOD "%s: Fatal error - "
+                       pr_err(KERN_ERR MOD "%s: Fatal error - "
                               "DB overflow recovery failed - "
                               "error syncing RQ qid %u\n",
                               pci_name(ctx->lldi.pdev), qp->wq.rq.qid);
+                       spin_unlock(&qp->lock);
+                       spin_unlock_irq(&qp->rhp->lock);
                        return;
                }
+               qp->wq.rq.wq_pidx_inc = 0;
+               spin_unlock(&qp->lock);
+               spin_unlock_irq(&qp->rhp->lock);
 
                /* Wait for the dbfifo to drain */
                while (cxgb4_dbfifo_count(qp->rhp->rdev.lldi.ports[0], 1) > 0) {
@@ -1083,36 +1152,22 @@ static void recover_queues(struct uld_ctx *ctx)
        struct qp_list qp_list;
        int ret;
 
-       /* lock out kernel db ringers */
-       mutex_lock(&ctx->dev->db_mutex);
-
-       /* put all queues in to recovery mode */
-       spin_lock_irq(&ctx->dev->lock);
-       ctx->dev->db_state = RECOVERY;
-       ctx->dev->rdev.stats.db_state_transitions++;
-       idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
-       spin_unlock_irq(&ctx->dev->lock);
-
        /* slow everybody down */
        set_current_state(TASK_UNINTERRUPTIBLE);
        schedule_timeout(usecs_to_jiffies(1000));
 
-       /* Wait for the dbfifo to completely drain. */
-       while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(usecs_to_jiffies(10));
-       }
-
        /* flush the SGE contexts */
        ret = cxgb4_flush_eq_cache(ctx->dev->rdev.lldi.ports[0]);
        if (ret) {
                printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
                       pci_name(ctx->lldi.pdev));
-               goto out;
+               return;
        }
 
        /* Count active queues so we can build a list of queues to recover */
        spin_lock_irq(&ctx->dev->lock);
+       WARN_ON(ctx->dev->db_state != STOPPED);
+       ctx->dev->db_state = RECOVERY;
        idr_for_each(&ctx->dev->qpidr, count_qps, &count);
 
        qp_list.qps = kzalloc(count * sizeof *qp_list.qps, GFP_ATOMIC);
@@ -1120,7 +1175,7 @@ static void recover_queues(struct uld_ctx *ctx)
                printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
                       pci_name(ctx->lldi.pdev));
                spin_unlock_irq(&ctx->dev->lock);
-               goto out;
+               return;
        }
        qp_list.idx = 0;
 
@@ -1133,29 +1188,13 @@ static void recover_queues(struct uld_ctx *ctx)
        recover_lost_dbs(ctx, &qp_list);
 
        /* we're almost done!  deref the qps and clean up */
-       deref_qps(qp_list);
+       deref_qps(&qp_list);
        kfree(qp_list.qps);
 
-       /* Wait for the dbfifo to completely drain again */
-       while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(usecs_to_jiffies(10));
-       }
-
-       /* resume the queues */
        spin_lock_irq(&ctx->dev->lock);
-       if (ctx->dev->qpcnt > db_fc_threshold)
-               ctx->dev->db_state = FLOW_CONTROL;
-       else {
-               ctx->dev->db_state = NORMAL;
-               idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
-       }
-       ctx->dev->rdev.stats.db_state_transitions++;
+       WARN_ON(ctx->dev->db_state != RECOVERY);
+       ctx->dev->db_state = STOPPED;
        spin_unlock_irq(&ctx->dev->lock);
-
-out:
-       /* start up kernel db ringers again */
-       mutex_unlock(&ctx->dev->db_mutex);
 }
 
 static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
@@ -1165,9 +1204,7 @@ static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
        switch (control) {
        case CXGB4_CONTROL_DB_FULL:
                stop_queues(ctx);
-               mutex_lock(&ctx->dev->rdev.stats.lock);
                ctx->dev->rdev.stats.db_full++;
-               mutex_unlock(&ctx->dev->rdev.stats.lock);
                break;
        case CXGB4_CONTROL_DB_EMPTY:
                resume_queues(ctx);
index 23eaeabab93b50d483e279de2adb7175c7c29dfc..eb18f9be35e4f84ffb64d4d8e24d6fbba1dd087d 100644 (file)
@@ -109,6 +109,7 @@ struct c4iw_dev_ucontext {
 
 enum c4iw_rdev_flags {
        T4_FATAL_ERROR = (1<<0),
+       T4_STATUS_PAGE_DISABLED = (1<<1),
 };
 
 struct c4iw_stat {
@@ -130,6 +131,7 @@ struct c4iw_stats {
        u64  db_empty;
        u64  db_drop;
        u64  db_state_transitions;
+       u64  db_fc_interruptions;
        u64  tcam_full;
        u64  act_ofld_conn_fails;
        u64  pas_ofld_conn_fails;
@@ -150,6 +152,7 @@ struct c4iw_rdev {
        unsigned long oc_mw_pa;
        void __iomem *oc_mw_kva;
        struct c4iw_stats stats;
+       struct t4_dev_status_page *status_page;
 };
 
 static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
@@ -211,7 +214,8 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
 enum db_state {
        NORMAL = 0,
        FLOW_CONTROL = 1,
-       RECOVERY = 2
+       RECOVERY = 2,
+       STOPPED = 3
 };
 
 struct c4iw_dev {
@@ -225,10 +229,10 @@ struct c4iw_dev {
        struct mutex db_mutex;
        struct dentry *debugfs_root;
        enum db_state db_state;
-       int qpcnt;
        struct idr hwtid_idr;
        struct idr atid_idr;
        struct idr stid_idr;
+       struct list_head db_fc_list;
 };
 
 static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
@@ -432,6 +436,7 @@ struct c4iw_qp_attributes {
 
 struct c4iw_qp {
        struct ib_qp ibqp;
+       struct list_head db_fc_entry;
        struct c4iw_dev *rhp;
        struct c4iw_ep *ep;
        struct c4iw_qp_attributes attr;
index 7e94c9a656a1429d37c14bd2e7b8f4b8590d494e..e36d2a27c4315bfbeedd6e67dc8fba535ca82ead 100644 (file)
@@ -106,15 +106,54 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
 {
        struct c4iw_ucontext *context;
        struct c4iw_dev *rhp = to_c4iw_dev(ibdev);
+       static int warned;
+       struct c4iw_alloc_ucontext_resp uresp;
+       int ret = 0;
+       struct c4iw_mm_entry *mm = NULL;
 
        PDBG("%s ibdev %p\n", __func__, ibdev);
        context = kzalloc(sizeof(*context), GFP_KERNEL);
-       if (!context)
-               return ERR_PTR(-ENOMEM);
+       if (!context) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
        c4iw_init_dev_ucontext(&rhp->rdev, &context->uctx);
        INIT_LIST_HEAD(&context->mmaps);
        spin_lock_init(&context->mmap_lock);
+
+       if (udata->outlen < sizeof(uresp)) {
+               if (!warned++)
+                       pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device status page disabled.");
+               rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED;
+       } else {
+               mm = kmalloc(sizeof(*mm), GFP_KERNEL);
+               if (!mm)
+                       goto err_free;
+
+               uresp.status_page_size = PAGE_SIZE;
+
+               spin_lock(&context->mmap_lock);
+               uresp.status_page_key = context->key;
+               context->key += PAGE_SIZE;
+               spin_unlock(&context->mmap_lock);
+
+               ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+               if (ret)
+                       goto err_mm;
+
+               mm->key = uresp.status_page_key;
+               mm->addr = virt_to_phys(rhp->rdev.status_page);
+               mm->len = PAGE_SIZE;
+               insert_mmap(context, mm);
+       }
        return &context->ibucontext;
+err_mm:
+       kfree(mm);
+err_free:
+       kfree(context);
+err:
+       return ERR_PTR(ret);
 }
 
 static int c4iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
index 582936708e6e492dfca46b88b5db98f16159c0db..3b62eb556a4780f56cfd5131ca69272a388523b4 100644 (file)
@@ -638,6 +638,46 @@ void c4iw_qp_rem_ref(struct ib_qp *qp)
                wake_up(&(to_c4iw_qp(qp)->wait));
 }
 
+static void add_to_fc_list(struct list_head *head, struct list_head *entry)
+{
+       if (list_empty(entry))
+               list_add_tail(entry, head);
+}
+
+static int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qhp->rhp->lock, flags);
+       spin_lock(&qhp->lock);
+       if (qhp->rhp->db_state == NORMAL) {
+               t4_ring_sq_db(&qhp->wq, inc);
+       } else {
+               add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
+               qhp->wq.sq.wq_pidx_inc += inc;
+       }
+       spin_unlock(&qhp->lock);
+       spin_unlock_irqrestore(&qhp->rhp->lock, flags);
+       return 0;
+}
+
+static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qhp->rhp->lock, flags);
+       spin_lock(&qhp->lock);
+       if (qhp->rhp->db_state == NORMAL) {
+               t4_ring_rq_db(&qhp->wq, inc);
+       } else {
+               add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
+               qhp->wq.rq.wq_pidx_inc += inc;
+       }
+       spin_unlock(&qhp->lock);
+       spin_unlock_irqrestore(&qhp->rhp->lock, flags);
+       return 0;
+}
+
 int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                   struct ib_send_wr **bad_wr)
 {
@@ -750,9 +790,13 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                t4_sq_produce(&qhp->wq, len16);
                idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
        }
-       if (t4_wq_db_enabled(&qhp->wq))
+       if (!qhp->rhp->rdev.status_page->db_off) {
                t4_ring_sq_db(&qhp->wq, idx);
-       spin_unlock_irqrestore(&qhp->lock, flag);
+               spin_unlock_irqrestore(&qhp->lock, flag);
+       } else {
+               spin_unlock_irqrestore(&qhp->lock, flag);
+               ring_kernel_sq_db(qhp, idx);
+       }
        return err;
 }
 
@@ -812,9 +856,13 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                wr = wr->next;
                num_wrs--;
        }
-       if (t4_wq_db_enabled(&qhp->wq))
+       if (!qhp->rhp->rdev.status_page->db_off) {
                t4_ring_rq_db(&qhp->wq, idx);
-       spin_unlock_irqrestore(&qhp->lock, flag);
+               spin_unlock_irqrestore(&qhp->lock, flag);
+       } else {
+               spin_unlock_irqrestore(&qhp->lock, flag);
+               ring_kernel_rq_db(qhp, idx);
+       }
        return err;
 }
 
@@ -1200,35 +1248,6 @@ out:
        return ret;
 }
 
-/*
- * Called by the library when the qp has user dbs disabled due to
- * a DB_FULL condition.  This function will single-thread all user
- * DB rings to avoid overflowing the hw db-fifo.
- */
-static int ring_kernel_db(struct c4iw_qp *qhp, u32 qid, u16 inc)
-{
-       int delay = db_delay_usecs;
-
-       mutex_lock(&qhp->rhp->db_mutex);
-       do {
-
-               /*
-                * The interrupt threshold is dbfifo_int_thresh << 6. So
-                * make sure we don't cross that and generate an interrupt.
-                */
-               if (cxgb4_dbfifo_count(qhp->rhp->rdev.lldi.ports[0], 1) <
-                   (qhp->rhp->rdev.lldi.dbfifo_int_thresh << 5)) {
-                       writel(QID(qid) | PIDX(inc), qhp->wq.db);
-                       break;
-               }
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(usecs_to_jiffies(delay));
-               delay = min(delay << 1, 2000);
-       } while (1);
-       mutex_unlock(&qhp->rhp->db_mutex);
-       return 0;
-}
-
 int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                   enum c4iw_qp_attr_mask mask,
                   struct c4iw_qp_attributes *attrs,
@@ -1278,11 +1297,11 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
        }
 
        if (mask & C4IW_QP_ATTR_SQ_DB) {
-               ret = ring_kernel_db(qhp, qhp->wq.sq.qid, attrs->sq_db_inc);
+               ret = ring_kernel_sq_db(qhp, attrs->sq_db_inc);
                goto out;
        }
        if (mask & C4IW_QP_ATTR_RQ_DB) {
-               ret = ring_kernel_db(qhp, qhp->wq.rq.qid, attrs->rq_db_inc);
+               ret = ring_kernel_rq_db(qhp, attrs->rq_db_inc);
                goto out;
        }
 
@@ -1465,14 +1484,6 @@ out:
        return ret;
 }
 
-static int enable_qp_db(int id, void *p, void *data)
-{
-       struct c4iw_qp *qp = p;
-
-       t4_enable_wq_db(&qp->wq);
-       return 0;
-}
-
 int c4iw_destroy_qp(struct ib_qp *ib_qp)
 {
        struct c4iw_dev *rhp;
@@ -1490,22 +1501,15 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
                c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
        wait_event(qhp->wait, !qhp->ep);
 
-       spin_lock_irq(&rhp->lock);
-       remove_handle_nolock(rhp, &rhp->qpidr, qhp->wq.sq.qid);
-       rhp->qpcnt--;
-       BUG_ON(rhp->qpcnt < 0);
-       if (rhp->qpcnt <= db_fc_threshold && rhp->db_state == FLOW_CONTROL) {
-               rhp->rdev.stats.db_state_transitions++;
-               rhp->db_state = NORMAL;
-               idr_for_each(&rhp->qpidr, enable_qp_db, NULL);
-       }
-       if (db_coalescing_threshold >= 0)
-               if (rhp->qpcnt <= db_coalescing_threshold)
-                       cxgb4_enable_db_coalescing(rhp->rdev.lldi.ports[0]);
-       spin_unlock_irq(&rhp->lock);
+       remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
        atomic_dec(&qhp->refcnt);
        wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
 
+       spin_lock_irq(&rhp->lock);
+       if (!list_empty(&qhp->db_fc_entry))
+               list_del_init(&qhp->db_fc_entry);
+       spin_unlock_irq(&rhp->lock);
+
        ucontext = ib_qp->uobject ?
                   to_c4iw_ucontext(ib_qp->uobject->context) : NULL;
        destroy_qp(&rhp->rdev, &qhp->wq,
@@ -1516,14 +1520,6 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
        return 0;
 }
 
-static int disable_qp_db(int id, void *p, void *data)
-{
-       struct c4iw_qp *qp = p;
-
-       t4_disable_wq_db(&qp->wq);
-       return 0;
-}
-
 struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                             struct ib_udata *udata)
 {
@@ -1610,20 +1606,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
        init_waitqueue_head(&qhp->wait);
        atomic_set(&qhp->refcnt, 1);
 
-       spin_lock_irq(&rhp->lock);
-       if (rhp->db_state != NORMAL)
-               t4_disable_wq_db(&qhp->wq);
-       rhp->qpcnt++;
-       if (rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) {
-               rhp->rdev.stats.db_state_transitions++;
-               rhp->db_state = FLOW_CONTROL;
-               idr_for_each(&rhp->qpidr, disable_qp_db, NULL);
-       }
-       if (db_coalescing_threshold >= 0)
-               if (rhp->qpcnt > db_coalescing_threshold)
-                       cxgb4_disable_db_coalescing(rhp->rdev.lldi.ports[0]);
-       ret = insert_handle_nolock(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
-       spin_unlock_irq(&rhp->lock);
+       ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
        if (ret)
                goto err2;
 
@@ -1709,6 +1692,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
        }
        qhp->ibqp.qp_num = qhp->wq.sq.qid;
        init_timer(&(qhp->timer));
+       INIT_LIST_HEAD(&qhp->db_fc_entry);
        PDBG("%s qhp %p sq_num_entries %d, rq_num_entries %d qpid 0x%0x\n",
             __func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
             qhp->wq.sq.qid);
index e73ace739183a9864ab8fee70e374cdc9ce0d178..eeca8b1e63764cbbd7e8f1a0760028730bd9e944 100644 (file)
@@ -300,6 +300,7 @@ struct t4_sq {
        u16 cidx;
        u16 pidx;
        u16 wq_pidx;
+       u16 wq_pidx_inc;
        u16 flags;
        short flush_cidx;
 };
@@ -324,6 +325,7 @@ struct t4_rq {
        u16 cidx;
        u16 pidx;
        u16 wq_pidx;
+       u16 wq_pidx_inc;
 };
 
 struct t4_wq {
@@ -609,3 +611,7 @@ static inline void t4_set_cq_in_error(struct t4_cq *cq)
        ((struct t4_status_page *)&cq->queue[cq->size])->qp_err = 1;
 }
 #endif
+
+struct t4_dev_status_page {
+       u8 db_off;
+};
index 32b754c35ab78f5f11f9e0014de8952df549e060..11ccd276e5d9c334d2cb3aa445ddaac1401483b7 100644 (file)
@@ -70,4 +70,9 @@ struct c4iw_create_qp_resp {
        __u32 qid_mask;
        __u32 flags;
 };
+
+struct c4iw_alloc_ucontext_resp {
+       __u64 status_page_key;
+       __u32 status_page_size;
+};
 #endif
index d1f5f1dd77b0db3d364fe447bd7f3259b4a0ff6d..56a593e0ae5d1f537db0f3615ee29eb99b0defc2 100644 (file)
@@ -61,6 +61,11 @@ struct cm_generic_msg {
        __be32 remote_comm_id;
 };
 
+struct cm_sidr_generic_msg {
+       struct ib_mad_hdr hdr;
+       __be32 request_id;
+};
+
 struct cm_req_msg {
        unsigned char unused[0x60];
        union ib_gid primary_path_sgid;
@@ -69,28 +74,62 @@ struct cm_req_msg {
 
 static void set_local_comm_id(struct ib_mad *mad, u32 cm_id)
 {
-       struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-       msg->local_comm_id = cpu_to_be32(cm_id);
+       if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               struct cm_sidr_generic_msg *msg =
+                       (struct cm_sidr_generic_msg *)mad;
+               msg->request_id = cpu_to_be32(cm_id);
+       } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+               pr_err("trying to set local_comm_id in SIDR_REP\n");
+               return;
+       } else {
+               struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+               msg->local_comm_id = cpu_to_be32(cm_id);
+       }
 }
 
 static u32 get_local_comm_id(struct ib_mad *mad)
 {
-       struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-
-       return be32_to_cpu(msg->local_comm_id);
+       if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               struct cm_sidr_generic_msg *msg =
+                       (struct cm_sidr_generic_msg *)mad;
+               return be32_to_cpu(msg->request_id);
+       } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+               pr_err("trying to set local_comm_id in SIDR_REP\n");
+               return -1;
+       } else {
+               struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+               return be32_to_cpu(msg->local_comm_id);
+       }
 }
 
 static void set_remote_comm_id(struct ib_mad *mad, u32 cm_id)
 {
-       struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-       msg->remote_comm_id = cpu_to_be32(cm_id);
+       if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+               struct cm_sidr_generic_msg *msg =
+                       (struct cm_sidr_generic_msg *)mad;
+               msg->request_id = cpu_to_be32(cm_id);
+       } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               pr_err("trying to set remote_comm_id in SIDR_REQ\n");
+               return;
+       } else {
+               struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+               msg->remote_comm_id = cpu_to_be32(cm_id);
+       }
 }
 
 static u32 get_remote_comm_id(struct ib_mad *mad)
 {
-       struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-
-       return be32_to_cpu(msg->remote_comm_id);
+       if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+               struct cm_sidr_generic_msg *msg =
+                       (struct cm_sidr_generic_msg *)mad;
+               return be32_to_cpu(msg->request_id);
+       } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               pr_err("trying to set remote_comm_id in SIDR_REQ\n");
+               return -1;
+       } else {
+               struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+               return be32_to_cpu(msg->remote_comm_id);
+       }
 }
 
 static union ib_gid gid_from_req_msg(struct ib_device *ibdev, struct ib_mad *mad)
@@ -282,19 +321,21 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
        u32 sl_cm_id;
        int pv_cm_id = -1;
 
-       sl_cm_id = get_local_comm_id(mad);
-
        if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID ||
-                       mad->mad_hdr.attr_id == CM_REP_ATTR_ID) {
+                       mad->mad_hdr.attr_id == CM_REP_ATTR_ID ||
+                       mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               sl_cm_id = get_local_comm_id(mad);
                id = id_map_alloc(ibdev, slave_id, sl_cm_id);
                if (IS_ERR(id)) {
                        mlx4_ib_warn(ibdev, "%s: id{slave: %d, sl_cm_id: 0x%x} Failed to id_map_alloc\n",
                                __func__, slave_id, sl_cm_id);
                        return PTR_ERR(id);
                }
-       } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID) {
+       } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID ||
+                  mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
                return 0;
        } else {
+               sl_cm_id = get_local_comm_id(mad);
                id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id);
        }
 
@@ -315,14 +356,18 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
 }
 
 int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
-                                                            struct ib_mad *mad)
+                            struct ib_mad *mad)
 {
        u32 pv_cm_id;
        struct id_map_entry *id;
 
-       if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID) {
+       if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID ||
+           mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
                union ib_gid gid;
 
+               if (!slave)
+                       return 0;
+
                gid = gid_from_req_msg(ibdev, mad);
                *slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id);
                if (*slave < 0) {
@@ -341,7 +386,8 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
                return -ENOENT;
        }
 
-       *slave = id->slave_id;
+       if (slave)
+               *slave = id->slave_id;
        set_remote_comm_id(mad, id->sl_cm_id);
 
        if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID)
index cc40f08ca8f1d353faafde91015ab13c247bad4b..5f640814cc81763e61fad3fb2bcdc50993a57a51 100644 (file)
@@ -564,7 +564,7 @@ static int mlx4_ib_ipoib_csum_ok(__be16 status, __be16 checksum)
 }
 
 static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct ib_wc *wc,
-                          unsigned tail, struct mlx4_cqe *cqe)
+                          unsigned tail, struct mlx4_cqe *cqe, int is_eth)
 {
        struct mlx4_ib_proxy_sqp_hdr *hdr;
 
@@ -574,12 +574,20 @@ static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct
                                   DMA_FROM_DEVICE);
        hdr = (struct mlx4_ib_proxy_sqp_hdr *) (qp->sqp_proxy_rcv[tail].addr);
        wc->pkey_index  = be16_to_cpu(hdr->tun.pkey_index);
-       wc->slid        = be16_to_cpu(hdr->tun.slid_mac_47_32);
-       wc->sl          = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12);
        wc->src_qp      = be32_to_cpu(hdr->tun.flags_src_qp) & 0xFFFFFF;
        wc->wc_flags   |= (hdr->tun.g_ml_path & 0x80) ? (IB_WC_GRH) : 0;
        wc->dlid_path_bits = 0;
 
+       if (is_eth) {
+               wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid);
+               memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4);
+               memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2);
+               wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC);
+       } else {
+               wc->slid        = be16_to_cpu(hdr->tun.slid_mac_47_32);
+               wc->sl          = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12);
+       }
+
        return 0;
 }
 
@@ -594,6 +602,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
        struct mlx4_srq *msrq = NULL;
        int is_send;
        int is_error;
+       int is_eth;
        u32 g_mlpath_rqpn;
        u16 wqe_ctr;
        unsigned tail = 0;
@@ -778,11 +787,15 @@ repoll:
                        break;
                }
 
+               is_eth = (rdma_port_get_link_layer(wc->qp->device,
+                                                 (*cur_qp)->port) ==
+                         IB_LINK_LAYER_ETHERNET);
                if (mlx4_is_mfunc(to_mdev(cq->ibcq.device)->dev)) {
                        if ((*cur_qp)->mlx4_ib_qp_type &
                            (MLX4_IB_QPT_PROXY_SMI_OWNER |
                             MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI))
-                               return use_tunnel_data(*cur_qp, cq, wc, tail, cqe);
+                               return use_tunnel_data(*cur_qp, cq, wc, tail,
+                                                      cqe, is_eth);
                }
 
                wc->slid           = be16_to_cpu(cqe->rlid);
@@ -793,20 +806,21 @@ repoll:
                wc->pkey_index     = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f;
                wc->wc_flags      |= mlx4_ib_ipoib_csum_ok(cqe->status,
                                        cqe->checksum) ? IB_WC_IP_CSUM_OK : 0;
-               if (rdma_port_get_link_layer(wc->qp->device,
-                               (*cur_qp)->port) == IB_LINK_LAYER_ETHERNET)
+               if (is_eth) {
                        wc->sl  = be16_to_cpu(cqe->sl_vid) >> 13;
-               else
-                       wc->sl  = be16_to_cpu(cqe->sl_vid) >> 12;
-               if (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_VLAN_PRESENT_MASK) {
-                       wc->vlan_id = be16_to_cpu(cqe->sl_vid) &
-                               MLX4_CQE_VID_MASK;
+                       if (be32_to_cpu(cqe->vlan_my_qpn) &
+                                       MLX4_CQE_VLAN_PRESENT_MASK) {
+                               wc->vlan_id = be16_to_cpu(cqe->sl_vid) &
+                                       MLX4_CQE_VID_MASK;
+                       } else {
+                               wc->vlan_id = 0xffff;
+                       }
+                       memcpy(wc->smac, cqe->smac, ETH_ALEN);
+                       wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC);
                } else {
+                       wc->sl  = be16_to_cpu(cqe->sl_vid) >> 12;
                        wc->vlan_id = 0xffff;
                }
-               wc->wc_flags |= IB_WC_WITH_VLAN;
-               memcpy(wc->smac, cqe->smac, ETH_ALEN);
-               wc->wc_flags |= IB_WC_WITH_SMAC;
        }
 
        return 0;
index f2a3f48107e71e1d53b0abb61757f1f0ba38bb59..2c572aed3f6f2a47c7bf849ab6c394c429ead9cb 100644 (file)
@@ -467,6 +467,7 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
        int ret = 0;
        u16 tun_pkey_ix;
        u16 cached_pkey;
+       u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
 
        if (dest_qpt > IB_QPT_GSI)
                return -EINVAL;
@@ -509,6 +510,10 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
         * The driver will set the force loopback bit in post_send */
        memset(&attr, 0, sizeof attr);
        attr.port_num = port;
+       if (is_eth) {
+               memcpy(&attr.grh.dgid.raw[0], &grh->dgid.raw[0], 16);
+               attr.ah_flags = IB_AH_GRH;
+       }
        ah = ib_create_ah(tun_ctx->pd, &attr);
        if (IS_ERR(ah))
                return -ENOMEM;
@@ -540,11 +545,36 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
 
        /* adjust tunnel data */
        tun_mad->hdr.pkey_index = cpu_to_be16(tun_pkey_ix);
-       tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12);
-       tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid);
        tun_mad->hdr.flags_src_qp = cpu_to_be32(wc->src_qp & 0xFFFFFF);
        tun_mad->hdr.g_ml_path = (grh && (wc->wc_flags & IB_WC_GRH)) ? 0x80 : 0;
 
+       if (is_eth) {
+               u16 vlan = 0;
+               if (mlx4_get_slave_default_vlan(dev->dev, port, slave, &vlan,
+                                               NULL)) {
+                       /* VST mode */
+                       if (vlan != wc->vlan_id)
+                               /* Packet vlan is not the VST-assigned vlan.
+                                * Drop the packet.
+                                */
+                               goto out;
+                        else
+                               /* Remove the vlan tag before forwarding
+                                * the packet to the VF.
+                                */
+                               vlan = 0xffff;
+               } else {
+                       vlan = wc->vlan_id;
+               }
+
+               tun_mad->hdr.sl_vid = cpu_to_be16(vlan);
+               memcpy((char *)&tun_mad->hdr.mac_31_0, &(wc->smac[0]), 4);
+               memcpy((char *)&tun_mad->hdr.slid_mac_47_32, &(wc->smac[4]), 2);
+       } else {
+               tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12);
+               tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid);
+       }
+
        ib_dma_sync_single_for_device(&dev->ib_dev,
                                      tun_qp->tx_ring[tun_tx_ix].buf.map,
                                      sizeof (struct mlx4_rcv_tunnel_mad),
@@ -580,6 +610,41 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port,
        int err;
        int slave;
        u8 *slave_id;
+       int is_eth = 0;
+
+       if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND)
+               is_eth = 0;
+       else
+               is_eth = 1;
+
+       if (is_eth) {
+               if (!(wc->wc_flags & IB_WC_GRH)) {
+                       mlx4_ib_warn(ibdev, "RoCE grh not present.\n");
+                       return -EINVAL;
+               }
+               if (mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_CM) {
+                       mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n");
+                       return -EINVAL;
+               }
+               if (mlx4_get_slave_from_roce_gid(dev->dev, port, grh->dgid.raw, &slave)) {
+                       mlx4_ib_warn(ibdev, "failed matching grh\n");
+                       return -ENOENT;
+               }
+               if (slave >= dev->dev->caps.sqp_demux) {
+                       mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n",
+                                    slave, dev->dev->caps.sqp_demux);
+                       return -ENOENT;
+               }
+
+               if (mlx4_ib_demux_cm_handler(ibdev, port, NULL, mad))
+                       return 0;
+
+               err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad);
+               if (err)
+                       pr_debug("failed sending to slave %d via tunnel qp (%d)\n",
+                                slave, err);
+               return 0;
+       }
 
        /* Initially assume that this mad is for us */
        slave = mlx4_master_func_num(dev->dev);
@@ -1076,8 +1141,9 @@ static int is_proxy_qp0(struct mlx4_ib_dev *dev, int qpn, int slave)
 
 
 int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
-                        enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn,
-                        u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad)
+                        enum ib_qp_type dest_qpt, u16 pkey_index,
+                        u32 remote_qpn, u32 qkey, struct ib_ah_attr *attr,
+                        u8 *s_mac, struct ib_mad *mad)
 {
        struct ib_sge list;
        struct ib_send_wr wr, *bad_wr;
@@ -1166,6 +1232,9 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
        wr.num_sge = 1;
        wr.opcode = IB_WR_SEND;
        wr.send_flags = IB_SEND_SIGNALED;
+       if (s_mac)
+               memcpy(to_mah(ah)->av.eth.s_mac, s_mac, 6);
+
 
        ret = ib_post_send(send_qp, &wr, &bad_wr);
 out:
@@ -1174,6 +1243,34 @@ out:
        return ret;
 }
 
+static int get_slave_base_gid_ix(struct mlx4_ib_dev *dev, int slave, int port)
+{
+       int gids;
+       int vfs;
+
+       if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND)
+               return slave;
+
+       gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
+       vfs = dev->dev->num_vfs;
+
+       if (slave == 0)
+               return 0;
+       if (slave <= gids % vfs)
+               return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1);
+
+       return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1));
+}
+
+static void fill_in_real_sgid_index(struct mlx4_ib_dev *dev, int slave, int port,
+                                   struct ib_ah_attr *ah_attr)
+{
+       if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND)
+               ah_attr->grh.sgid_index = slave;
+       else
+               ah_attr->grh.sgid_index += get_slave_base_gid_ix(dev, slave, port);
+}
+
 static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc *wc)
 {
        struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev);
@@ -1260,12 +1357,14 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
        memcpy(&ah.av, &tunnel->hdr.av, sizeof (struct mlx4_av));
        ah.ibah.device = ctx->ib_dev;
        mlx4_ib_query_ah(&ah.ibah, &ah_attr);
-       if ((ah_attr.ah_flags & IB_AH_GRH) &&
-           (ah_attr.grh.sgid_index != slave)) {
-               mlx4_ib_warn(ctx->ib_dev, "slave:%d accessed invalid sgid_index:%d\n",
-                            slave, ah_attr.grh.sgid_index);
-               return;
-       }
+       if (ah_attr.ah_flags & IB_AH_GRH)
+               fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr);
+
+       memcpy(ah_attr.dmac, tunnel->hdr.mac, 6);
+       ah_attr.vlan_id = be16_to_cpu(tunnel->hdr.vlan);
+       /* if slave have default vlan use it */
+       mlx4_get_slave_default_vlan(dev->dev, ctx->port, slave,
+                                   &ah_attr.vlan_id, &ah_attr.sl);
 
        mlx4_ib_send_to_wire(dev, slave, ctx->port,
                             is_proxy_qp0(dev, wc->src_qp, slave) ?
@@ -1273,7 +1372,7 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
                             be16_to_cpu(tunnel->hdr.pkey_index),
                             be32_to_cpu(tunnel->hdr.remote_qpn),
                             be32_to_cpu(tunnel->hdr.qkey),
-                            &ah_attr, &tunnel->mad);
+                            &ah_attr, wc->smac, &tunnel->mad);
 }
 
 static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx,
index e81c5547e6479a87683dba621c169529f4209d5a..1d1750ef000ac32447d9e16084cc77b640068e69 100644 (file)
@@ -53,8 +53,8 @@
 #include "user.h"
 
 #define DRV_NAME       MLX4_IB_DRV_NAME
-#define DRV_VERSION    "1.0"
-#define DRV_RELDATE    "April 4, 2008"
+#define DRV_VERSION    "2.2-1"
+#define DRV_RELDATE    "Feb 2014"
 
 #define MLX4_IB_FLOW_MAX_PRIO 0xFFF
 #define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF
@@ -1888,14 +1888,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
 
        pr_info_once("%s", mlx4_ib_version);
 
-       mlx4_foreach_non_ib_transport_port(i, dev)
-               num_ports++;
-
-       if (mlx4_is_mfunc(dev) && num_ports) {
-               dev_err(&dev->pdev->dev, "RoCE is not supported over SRIOV as yet\n");
-               return NULL;
-       }
-
        num_ports = 0;
        mlx4_foreach_ib_transport_port(i, dev)
                num_ports++;
index 25b2cdff00f8e4bcd76044e8916b2aa257a7276e..ed327e6c8fdca54baf19c3ded92d60776cc1adbf 100644 (file)
@@ -215,8 +215,9 @@ static int send_mad_to_wire(struct mlx4_ib_demux_ctx *ctx, struct ib_mad *mad)
        }
        mlx4_ib_query_ah(dev->sm_ah[ctx->port - 1], &ah_attr);
        spin_unlock(&dev->sm_lock);
-       return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev), ctx->port,
-                                   IB_QPT_GSI, 0, 1, IB_QP1_QKEY, &ah_attr, mad);
+       return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev),
+                                   ctx->port, IB_QPT_GSI, 0, 1, IB_QP1_QKEY,
+                                   &ah_attr, NULL, mad);
 }
 
 static int send_mad_to_slave(int slave, struct mlx4_ib_demux_ctx *ctx,
index a230683af940663a214ca611f28f842d956270ba..f589522fddfd9efa4e32fdd0a7e8f63e49a54927 100644 (file)
@@ -241,6 +241,22 @@ struct mlx4_ib_proxy_sqp_hdr {
        struct mlx4_rcv_tunnel_hdr tun;
 }  __packed;
 
+struct mlx4_roce_smac_vlan_info {
+       u64 smac;
+       int smac_index;
+       int smac_port;
+       u64 candidate_smac;
+       int candidate_smac_index;
+       int candidate_smac_port;
+       u16 vid;
+       int vlan_index;
+       int vlan_port;
+       u16 candidate_vid;
+       int candidate_vlan_index;
+       int candidate_vlan_port;
+       int update_vid;
+};
+
 struct mlx4_ib_qp {
        struct ib_qp            ibqp;
        struct mlx4_qp          mqp;
@@ -273,8 +289,9 @@ struct mlx4_ib_qp {
        struct list_head        gid_list;
        struct list_head        steering_rules;
        struct mlx4_ib_buf      *sqp_proxy_rcv;
+       struct mlx4_roce_smac_vlan_info pri;
+       struct mlx4_roce_smac_vlan_info alt;
        u64                     reg_id;
-
 };
 
 struct mlx4_ib_srq {
@@ -720,9 +737,12 @@ void mlx4_ib_tunnels_update_work(struct work_struct *work);
 int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
                          enum ib_qp_type qpt, struct ib_wc *wc,
                          struct ib_grh *grh, struct ib_mad *mad);
+
 int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
                         enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn,
-                        u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad);
+                        u32 qkey, struct ib_ah_attr *attr, u8 *s_mac,
+                        struct ib_mad *mad);
+
 __be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx);
 
 int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
index d8f4d1fe849430ceb40eab47470d5af033884694..aadf7f82e1f388e387d053637da2e9b12fda22e2 100644 (file)
@@ -662,10 +662,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                        if (!sqp)
                                return -ENOMEM;
                        qp = &sqp->qp;
+                       qp->pri.vid = 0xFFFF;
+                       qp->alt.vid = 0xFFFF;
                } else {
                        qp = kzalloc(sizeof (struct mlx4_ib_qp), GFP_KERNEL);
                        if (!qp)
                                return -ENOMEM;
+                       qp->pri.vid = 0xFFFF;
+                       qp->alt.vid = 0xFFFF;
                }
        } else
                qp = *caller_qp;
@@ -940,11 +944,32 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
 {
        struct mlx4_ib_cq *send_cq, *recv_cq;
 
-       if (qp->state != IB_QPS_RESET)
+       if (qp->state != IB_QPS_RESET) {
                if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state),
                                   MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp))
                        pr_warn("modify QP %06x to RESET failed.\n",
                               qp->mqp.qpn);
+               if (qp->pri.smac) {
+                       mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
+                       qp->pri.smac = 0;
+               }
+               if (qp->alt.smac) {
+                       mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
+                       qp->alt.smac = 0;
+               }
+               if (qp->pri.vid < 0x1000) {
+                       mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid);
+                       qp->pri.vid = 0xFFFF;
+                       qp->pri.candidate_vid = 0xFFFF;
+                       qp->pri.update_vid = 0;
+               }
+               if (qp->alt.vid < 0x1000) {
+                       mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid);
+                       qp->alt.vid = 0xFFFF;
+                       qp->alt.candidate_vid = 0xFFFF;
+                       qp->alt.update_vid = 0;
+               }
+       }
 
        get_cqs(qp, &send_cq, &recv_cq);
 
@@ -1057,6 +1082,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
                qp = kzalloc(sizeof *qp, GFP_KERNEL);
                if (!qp)
                        return ERR_PTR(-ENOMEM);
+               qp->pri.vid = 0xFFFF;
+               qp->alt.vid = 0xFFFF;
                /* fall through */
        case IB_QPT_UD:
        {
@@ -1188,12 +1215,13 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port)
 
 static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
                          u64 smac, u16 vlan_tag, struct mlx4_qp_path *path,
-                         u8 port)
+                         struct mlx4_roce_smac_vlan_info *smac_info, u8 port)
 {
        int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) ==
                IB_LINK_LAYER_ETHERNET;
        int vidx;
        int smac_index;
+       int err;
 
 
        path->grh_mylmc     = ah->src_path_bits & 0x7f;
@@ -1223,61 +1251,103 @@ static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
        }
 
        if (is_eth) {
-               path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
-                       ((port - 1) << 6) | ((ah->sl & 7) << 3);
-
                if (!(ah->ah_flags & IB_AH_GRH))
                        return -1;
 
-               memcpy(path->dmac, ah->dmac, ETH_ALEN);
-               path->ackto = MLX4_IB_LINK_TYPE_ETH;
-               /* find the index  into MAC table for IBoE */
-               if (!is_zero_ether_addr((const u8 *)&smac)) {
-                       if (mlx4_find_cached_mac(dev->dev, port, smac,
-                                                &smac_index))
-                               return -ENOENT;
-               } else {
-                       smac_index = 0;
-               }
-
-               path->grh_mylmc &= 0x80 | smac_index;
+               path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
+                       ((port - 1) << 6) | ((ah->sl & 7) << 3);
 
                path->feup |= MLX4_FEUP_FORCE_ETH_UP;
                if (vlan_tag < 0x1000) {
-                       if (mlx4_find_cached_vlan(dev->dev, port, vlan_tag, &vidx))
-                               return -ENOENT;
-
-                       path->vlan_index = vidx;
-                       path->fl = 1 << 6;
+                       if (smac_info->vid < 0x1000) {
+                               /* both valid vlan ids */
+                               if (smac_info->vid != vlan_tag) {
+                                       /* different VIDs.  unreg old and reg new */
+                                       err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx);
+                                       if (err)
+                                               return err;
+                                       smac_info->candidate_vid = vlan_tag;
+                                       smac_info->candidate_vlan_index = vidx;
+                                       smac_info->candidate_vlan_port = port;
+                                       smac_info->update_vid = 1;
+                                       path->vlan_index = vidx;
+                               } else {
+                                       path->vlan_index = smac_info->vlan_index;
+                               }
+                       } else {
+                               /* no current vlan tag in qp */
+                               err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx);
+                               if (err)
+                                       return err;
+                               smac_info->candidate_vid = vlan_tag;
+                               smac_info->candidate_vlan_index = vidx;
+                               smac_info->candidate_vlan_port = port;
+                               smac_info->update_vid = 1;
+                               path->vlan_index = vidx;
+                       }
                        path->feup |= MLX4_FVL_FORCE_ETH_VLAN;
+                       path->fl = 1 << 6;
+               } else {
+                       /* have current vlan tag. unregister it at modify-qp success */
+                       if (smac_info->vid < 0x1000) {
+                               smac_info->candidate_vid = 0xFFFF;
+                               smac_info->update_vid = 1;
+                       }
                }
-       } else
+
+               /* get smac_index for RoCE use.
+                * If no smac was yet assigned, register one.
+                * If one was already assigned, but the new mac differs,
+                * unregister the old one and register the new one.
+               */
+               if (!smac_info->smac || smac_info->smac != smac) {
+                       /* register candidate now, unreg if needed, after success */
+                       smac_index = mlx4_register_mac(dev->dev, port, smac);
+                       if (smac_index >= 0) {
+                               smac_info->candidate_smac_index = smac_index;
+                               smac_info->candidate_smac = smac;
+                               smac_info->candidate_smac_port = port;
+                       } else {
+                               return -EINVAL;
+                       }
+               } else {
+                       smac_index = smac_info->smac_index;
+               }
+
+               memcpy(path->dmac, ah->dmac, 6);
+               path->ackto = MLX4_IB_LINK_TYPE_ETH;
+               /* put MAC table smac index for IBoE */
+               path->grh_mylmc = (u8) (smac_index) | 0x80;
+       } else {
                path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
                        ((port - 1) << 6) | ((ah->sl & 0xf) << 2);
+       }
 
        return 0;
 }
 
 static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_qp_attr *qp,
                         enum ib_qp_attr_mask qp_attr_mask,
+                        struct mlx4_ib_qp *mqp,
                         struct mlx4_qp_path *path, u8 port)
 {
        return _mlx4_set_path(dev, &qp->ah_attr,
                              mlx4_mac_to_u64((u8 *)qp->smac),
                              (qp_attr_mask & IB_QP_VID) ? qp->vlan_id : 0xffff,
-                             path, port);
+                             path, &mqp->pri, port);
 }
 
 static int mlx4_set_alt_path(struct mlx4_ib_dev *dev,
                             const struct ib_qp_attr *qp,
                             enum ib_qp_attr_mask qp_attr_mask,
+                            struct mlx4_ib_qp *mqp,
                             struct mlx4_qp_path *path, u8 port)
 {
        return _mlx4_set_path(dev, &qp->alt_ah_attr,
                              mlx4_mac_to_u64((u8 *)qp->alt_smac),
                              (qp_attr_mask & IB_QP_ALT_VID) ?
                              qp->alt_vlan_id : 0xffff,
-                             path, port);
+                             path, &mqp->alt, port);
 }
 
 static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
@@ -1292,6 +1362,37 @@ static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
        }
 }
 
+static int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, u8 *smac,
+                                   struct mlx4_qp_context *context)
+{
+       struct net_device *ndev;
+       u64 u64_mac;
+       int smac_index;
+
+
+       ndev = dev->iboe.netdevs[qp->port - 1];
+       if (ndev) {
+               smac = ndev->dev_addr;
+               u64_mac = mlx4_mac_to_u64(smac);
+       } else {
+               u64_mac = dev->dev->caps.def_mac[qp->port];
+       }
+
+       context->pri_path.sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | ((qp->port - 1) << 6);
+       if (!qp->pri.smac) {
+               smac_index = mlx4_register_mac(dev->dev, qp->port, u64_mac);
+               if (smac_index >= 0) {
+                       qp->pri.candidate_smac_index = smac_index;
+                       qp->pri.candidate_smac = u64_mac;
+                       qp->pri.candidate_smac_port = qp->port;
+                       context->pri_path.grh_mylmc = 0x80 | (u8) smac_index;
+               } else {
+                       return -ENOENT;
+               }
+       }
+       return 0;
+}
+
 static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                               const struct ib_qp_attr *attr, int attr_mask,
                               enum ib_qp_state cur_state, enum ib_qp_state new_state)
@@ -1403,7 +1504,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        }
 
        if (attr_mask & IB_QP_AV) {
-               if (mlx4_set_path(dev, attr, attr_mask, &context->pri_path,
+               if (mlx4_set_path(dev, attr, attr_mask, qp, &context->pri_path,
                                  attr_mask & IB_QP_PORT ?
                                  attr->port_num : qp->port))
                        goto out;
@@ -1426,7 +1527,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                    dev->dev->caps.pkey_table_len[attr->alt_port_num])
                        goto out;
 
-               if (mlx4_set_alt_path(dev, attr, attr_mask, &context->alt_path,
+               if (mlx4_set_alt_path(dev, attr, attr_mask, qp,
+                                     &context->alt_path,
                                      attr->alt_port_num))
                        goto out;
 
@@ -1532,6 +1634,20 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                                context->pri_path.fl = 0x80;
                        context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE;
                }
+               if (rdma_port_get_link_layer(&dev->ib_dev, qp->port) ==
+                   IB_LINK_LAYER_ETHERNET) {
+                       if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI ||
+                           qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI)
+                               context->pri_path.feup = 1 << 7; /* don't fsm */
+                       /* handle smac_index */
+                       if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_UD ||
+                           qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI ||
+                           qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) {
+                               err = handle_eth_ud_smac_index(dev, qp, (u8 *)attr->smac, context);
+                               if (err)
+                                       return -EINVAL;
+                       }
+               }
        }
 
        if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET)
@@ -1619,28 +1735,113 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
         * If we moved a kernel QP to RESET, clean up all old CQ
         * entries and reinitialize the QP.
         */
-       if (new_state == IB_QPS_RESET && !ibqp->uobject) {
-               mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
-                                ibqp->srq ? to_msrq(ibqp->srq): NULL);
-               if (send_cq != recv_cq)
-                       mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+       if (new_state == IB_QPS_RESET) {
+               if (!ibqp->uobject) {
+                       mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
+                                        ibqp->srq ? to_msrq(ibqp->srq) : NULL);
+                       if (send_cq != recv_cq)
+                               mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+
+                       qp->rq.head = 0;
+                       qp->rq.tail = 0;
+                       qp->sq.head = 0;
+                       qp->sq.tail = 0;
+                       qp->sq_next_wqe = 0;
+                       if (qp->rq.wqe_cnt)
+                               *qp->db.db  = 0;
 
-               qp->rq.head = 0;
-               qp->rq.tail = 0;
-               qp->sq.head = 0;
-               qp->sq.tail = 0;
-               qp->sq_next_wqe = 0;
-               if (qp->rq.wqe_cnt)
-                       *qp->db.db  = 0;
+                       if (qp->flags & MLX4_IB_QP_NETIF)
+                               mlx4_ib_steer_qp_reg(dev, qp, 0);
+               }
+               if (qp->pri.smac) {
+                       mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
+                       qp->pri.smac = 0;
+               }
+               if (qp->alt.smac) {
+                       mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
+                       qp->alt.smac = 0;
+               }
+               if (qp->pri.vid < 0x1000) {
+                       mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid);
+                       qp->pri.vid = 0xFFFF;
+                       qp->pri.candidate_vid = 0xFFFF;
+                       qp->pri.update_vid = 0;
+               }
 
-               if (qp->flags & MLX4_IB_QP_NETIF)
-                       mlx4_ib_steer_qp_reg(dev, qp, 0);
+               if (qp->alt.vid < 0x1000) {
+                       mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid);
+                       qp->alt.vid = 0xFFFF;
+                       qp->alt.candidate_vid = 0xFFFF;
+                       qp->alt.update_vid = 0;
+               }
        }
-
 out:
        if (err && steer_qp)
                mlx4_ib_steer_qp_reg(dev, qp, 0);
        kfree(context);
+       if (qp->pri.candidate_smac) {
+               if (err) {
+                       mlx4_unregister_mac(dev->dev, qp->pri.candidate_smac_port, qp->pri.candidate_smac);
+               } else {
+                       if (qp->pri.smac)
+                               mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
+                       qp->pri.smac = qp->pri.candidate_smac;
+                       qp->pri.smac_index = qp->pri.candidate_smac_index;
+                       qp->pri.smac_port = qp->pri.candidate_smac_port;
+               }
+               qp->pri.candidate_smac = 0;
+               qp->pri.candidate_smac_index = 0;
+               qp->pri.candidate_smac_port = 0;
+       }
+       if (qp->alt.candidate_smac) {
+               if (err) {
+                       mlx4_unregister_mac(dev->dev, qp->alt.candidate_smac_port, qp->alt.candidate_smac);
+               } else {
+                       if (qp->alt.smac)
+                               mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
+                       qp->alt.smac = qp->alt.candidate_smac;
+                       qp->alt.smac_index = qp->alt.candidate_smac_index;
+                       qp->alt.smac_port = qp->alt.candidate_smac_port;
+               }
+               qp->alt.candidate_smac = 0;
+               qp->alt.candidate_smac_index = 0;
+               qp->alt.candidate_smac_port = 0;
+       }
+
+       if (qp->pri.update_vid) {
+               if (err) {
+                       if (qp->pri.candidate_vid < 0x1000)
+                               mlx4_unregister_vlan(dev->dev, qp->pri.candidate_vlan_port,
+                                                    qp->pri.candidate_vid);
+               } else {
+                       if (qp->pri.vid < 0x1000)
+                               mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port,
+                                                    qp->pri.vid);
+                       qp->pri.vid = qp->pri.candidate_vid;
+                       qp->pri.vlan_port = qp->pri.candidate_vlan_port;
+                       qp->pri.vlan_index =  qp->pri.candidate_vlan_index;
+               }
+               qp->pri.candidate_vid = 0xFFFF;
+               qp->pri.update_vid = 0;
+       }
+
+       if (qp->alt.update_vid) {
+               if (err) {
+                       if (qp->alt.candidate_vid < 0x1000)
+                               mlx4_unregister_vlan(dev->dev, qp->alt.candidate_vlan_port,
+                                                    qp->alt.candidate_vid);
+               } else {
+                       if (qp->alt.vid < 0x1000)
+                               mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port,
+                                                    qp->alt.vid);
+                       qp->alt.vid = qp->alt.candidate_vid;
+                       qp->alt.vlan_port = qp->alt.candidate_vlan_port;
+                       qp->alt.vlan_index =  qp->alt.candidate_vlan_index;
+               }
+               qp->alt.candidate_vid = 0xFFFF;
+               qp->alt.update_vid = 0;
+       }
+
        return err;
 }
 
@@ -1842,9 +2043,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
 {
        struct ib_device *ib_dev = sqp->qp.ibqp.device;
        struct mlx4_wqe_mlx_seg *mlx = wqe;
+       struct mlx4_wqe_ctrl_seg *ctrl = wqe;
        struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
        struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
-       struct net_device *ndev;
        union ib_gid sgid;
        u16 pkey;
        int send_size;
@@ -1868,12 +2069,11 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                        /* When multi-function is enabled, the ib_core gid
                         * indexes don't necessarily match the hw ones, so
                         * we must use our own cache */
-                       sgid.global.subnet_prefix =
-                               to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
-                               subnet_prefix;
-                       sgid.global.interface_id =
-                               to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
-                               guid_cache[ah->av.ib.gid_index];
+                       err = mlx4_get_roce_gid_from_slave(to_mdev(ib_dev)->dev,
+                                                          be32_to_cpu(ah->av.ib.port_pd) >> 24,
+                                                          ah->av.ib.gid_index, &sgid.raw[0]);
+                       if (err)
+                               return err;
                } else  {
                        err = ib_get_cached_gid(ib_dev,
                                                be32_to_cpu(ah->av.ib.port_pd) >> 24,
@@ -1902,6 +2102,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                sqp->ud_header.grh.flow_label    =
                        ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
                sqp->ud_header.grh.hop_limit     = ah->av.ib.hop_limit;
+               if (is_eth)
+                       memcpy(sqp->ud_header.grh.source_gid.raw, sgid.raw, 16);
+               else {
                if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) {
                        /* When multi-function is enabled, the ib_core gid
                         * indexes don't necessarily match the hw ones, so
@@ -1917,6 +2120,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                                          be32_to_cpu(ah->av.ib.port_pd) >> 24,
                                          ah->av.ib.gid_index,
                                          &sqp->ud_header.grh.source_gid);
+               }
                memcpy(sqp->ud_header.grh.destination_gid.raw,
                       ah->av.ib.dgid, 16);
        }
@@ -1949,16 +2153,23 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
 
        if (is_eth) {
                u8 *smac;
+               struct in6_addr in6;
+
                u16 pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13;
 
                mlx->sched_prio = cpu_to_be16(pcp);
 
                memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
                /* FIXME: cache smac value? */
-               ndev = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1];
-               if (!ndev)
-                       return -ENODEV;
-               smac = ndev->dev_addr;
+               memcpy(&ctrl->srcrb_flags16[0], ah->av.eth.mac, 2);
+               memcpy(&ctrl->imm, ah->av.eth.mac + 2, 4);
+               memcpy(&in6, sgid.raw, sizeof(in6));
+
+               if (!mlx4_is_mfunc(to_mdev(ib_dev)->dev))
+                       smac = to_mdev(sqp->qp.ibqp.device)->
+                               iboe.netdevs[sqp->qp.port - 1]->dev_addr;
+               else    /* use the src mac of the tunnel */
+                       smac = ah->av.eth.s_mac;
                memcpy(sqp->ud_header.eth.smac_h, smac, 6);
                if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
                        mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
@@ -2190,6 +2401,8 @@ static void build_tunnel_header(struct ib_send_wr *wr, void *wqe, unsigned *mlx_
        hdr.remote_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
        hdr.pkey_index = cpu_to_be16(wr->wr.ud.pkey_index);
        hdr.qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+       memcpy(hdr.mac, ah->av.eth.mac, 6);
+       hdr.vlan = ah->av.eth.vlan;
 
        spc = MLX4_INLINE_ALIGN -
                ((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1));
index aa03e732b6a88d7cfa81a3d9ba4dee61d8f6c70d..bf900579ac08b4cae5ac09320b5189727b292485 100644 (file)
@@ -46,8 +46,8 @@
 #include "mlx5_ib.h"
 
 #define DRIVER_NAME "mlx5_ib"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
 
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver");
index d18d08a076e8e4a15a67f71d8eb8089dd976198d..8ee228e9ab5aa28b85ee2893a92b3ab243c35388 100644 (file)
@@ -492,12 +492,11 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        isert_conn->state = ISER_CONN_INIT;
        INIT_LIST_HEAD(&isert_conn->conn_accept_node);
        init_completion(&isert_conn->conn_login_comp);
-       init_waitqueue_head(&isert_conn->conn_wait);
-       init_waitqueue_head(&isert_conn->conn_wait_comp_err);
+       init_completion(&isert_conn->conn_wait);
+       init_completion(&isert_conn->conn_wait_comp_err);
        kref_init(&isert_conn->conn_kref);
        kref_get(&isert_conn->conn_kref);
        mutex_init(&isert_conn->conn_mutex);
-       mutex_init(&isert_conn->conn_comp_mutex);
        spin_lock_init(&isert_conn->conn_lock);
 
        cma_id->context = isert_conn;
@@ -688,11 +687,11 @@ isert_disconnect_work(struct work_struct *work)
 
        pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
        mutex_lock(&isert_conn->conn_mutex);
-       isert_conn->state = ISER_CONN_DOWN;
+       if (isert_conn->state == ISER_CONN_UP)
+               isert_conn->state = ISER_CONN_TERMINATING;
 
        if (isert_conn->post_recv_buf_count == 0 &&
            atomic_read(&isert_conn->post_send_buf_count) == 0) {
-               pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
                mutex_unlock(&isert_conn->conn_mutex);
                goto wake_up;
        }
@@ -712,7 +711,7 @@ isert_disconnect_work(struct work_struct *work)
        mutex_unlock(&isert_conn->conn_mutex);
 
 wake_up:
-       wake_up(&isert_conn->conn_wait);
+       complete(&isert_conn->conn_wait);
        isert_put_conn(isert_conn);
 }
 
@@ -888,16 +887,17 @@ isert_init_send_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
         * Coalesce send completion interrupts by only setting IB_SEND_SIGNALED
         * bit for every ISERT_COMP_BATCH_COUNT number of ib_post_send() calls.
         */
-       mutex_lock(&isert_conn->conn_comp_mutex);
-       if (coalesce &&
+       mutex_lock(&isert_conn->conn_mutex);
+       if (coalesce && isert_conn->state == ISER_CONN_UP &&
            ++isert_conn->conn_comp_batch < ISERT_COMP_BATCH_COUNT) {
+               tx_desc->llnode_active = true;
                llist_add(&tx_desc->comp_llnode, &isert_conn->conn_comp_llist);
-               mutex_unlock(&isert_conn->conn_comp_mutex);
+               mutex_unlock(&isert_conn->conn_mutex);
                return;
        }
        isert_conn->conn_comp_batch = 0;
        tx_desc->comp_llnode_batch = llist_del_all(&isert_conn->conn_comp_llist);
-       mutex_unlock(&isert_conn->conn_comp_mutex);
+       mutex_unlock(&isert_conn->conn_mutex);
 
        send_wr->send_flags = IB_SEND_SIGNALED;
 }
@@ -1464,7 +1464,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
        case ISCSI_OP_SCSI_CMD:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                if (cmd->data_direction == DMA_TO_DEVICE)
@@ -1476,7 +1476,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
        case ISCSI_OP_SCSI_TMFUNC:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                transport_generic_free_cmd(&cmd->se_cmd, 0);
@@ -1486,7 +1486,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
        case ISCSI_OP_TEXT:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                /*
@@ -1549,6 +1549,7 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc,
        iscsit_stop_dataout_timer(cmd);
        device->unreg_rdma_mem(isert_cmd, isert_conn);
        cmd->write_data_done = wr->cur_rdma_length;
+       wr->send_wr_num = 0;
 
        pr_debug("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd);
        spin_lock_bh(&cmd->istate_lock);
@@ -1589,7 +1590,7 @@ isert_do_control_comp(struct work_struct *work)
                pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
                /*
                 * Call atomic_dec(&isert_conn->post_send_buf_count)
-                * from isert_free_conn()
+                * from isert_wait_conn()
                 */
                isert_conn->logout_posted = true;
                iscsit_logout_post_handler(cmd, cmd->conn);
@@ -1613,6 +1614,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
                          struct ib_device *ib_dev)
 {
        struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
+       struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
 
        if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
            cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
@@ -1624,7 +1626,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
                queue_work(isert_comp_wq, &isert_cmd->comp_work);
                return;
        }
-       atomic_dec(&isert_conn->post_send_buf_count);
+       atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
 
        cmd->i_state = ISTATE_SENT_STATUS;
        isert_completion_put(tx_desc, isert_cmd, ib_dev);
@@ -1662,7 +1664,7 @@ __isert_send_completion(struct iser_tx_desc *tx_desc,
        case ISER_IB_RDMA_READ:
                pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n");
 
-               atomic_dec(&isert_conn->post_send_buf_count);
+               atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
                isert_completion_rdma_read(tx_desc, isert_cmd);
                break;
        default:
@@ -1691,31 +1693,76 @@ isert_send_completion(struct iser_tx_desc *tx_desc,
 }
 
 static void
-isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
+isert_cq_drain_comp_llist(struct isert_conn *isert_conn, struct ib_device *ib_dev)
+{
+       struct llist_node *llnode;
+       struct isert_rdma_wr *wr;
+       struct iser_tx_desc *t;
+
+       mutex_lock(&isert_conn->conn_mutex);
+       llnode = llist_del_all(&isert_conn->conn_comp_llist);
+       isert_conn->conn_comp_batch = 0;
+       mutex_unlock(&isert_conn->conn_mutex);
+
+       while (llnode) {
+               t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+               llnode = llist_next(llnode);
+               wr = &t->isert_cmd->rdma_wr;
+
+               atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+               isert_completion_put(t, t->isert_cmd, ib_dev);
+       }
+}
+
+static void
+isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
 {
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+       struct llist_node *llnode = tx_desc->comp_llnode_batch;
+       struct isert_rdma_wr *wr;
+       struct iser_tx_desc *t;
 
-       if (tx_desc) {
-               struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+       while (llnode) {
+               t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+               llnode = llist_next(llnode);
+               wr = &t->isert_cmd->rdma_wr;
 
-               if (!isert_cmd)
-                       isert_unmap_tx_desc(tx_desc, ib_dev);
-               else
-                       isert_completion_put(tx_desc, isert_cmd, ib_dev);
+               atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+               isert_completion_put(t, t->isert_cmd, ib_dev);
        }
+       tx_desc->comp_llnode_batch = NULL;
 
-       if (isert_conn->post_recv_buf_count == 0 &&
-           atomic_read(&isert_conn->post_send_buf_count) == 0) {
-               pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
-               pr_debug("Calling wake_up from isert_cq_comp_err\n");
+       if (!isert_cmd)
+               isert_unmap_tx_desc(tx_desc, ib_dev);
+       else
+               isert_completion_put(tx_desc, isert_cmd, ib_dev);
+}
 
-               mutex_lock(&isert_conn->conn_mutex);
-               if (isert_conn->state != ISER_CONN_DOWN)
-                       isert_conn->state = ISER_CONN_TERMINATING;
-               mutex_unlock(&isert_conn->conn_mutex);
+static void
+isert_cq_rx_comp_err(struct isert_conn *isert_conn)
+{
+       struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct iscsi_conn *conn = isert_conn->conn;
 
-               wake_up(&isert_conn->conn_wait_comp_err);
+       if (isert_conn->post_recv_buf_count)
+               return;
+
+       isert_cq_drain_comp_llist(isert_conn, ib_dev);
+
+       if (conn->sess) {
+               target_sess_cmd_list_set_waiting(conn->sess->se_sess);
+               target_wait_for_sess_cmds(conn->sess->se_sess);
        }
+
+       while (atomic_read(&isert_conn->post_send_buf_count))
+               msleep(3000);
+
+       mutex_lock(&isert_conn->conn_mutex);
+       isert_conn->state = ISER_CONN_DOWN;
+       mutex_unlock(&isert_conn->conn_mutex);
+
+       complete(&isert_conn->conn_wait_comp_err);
 }
 
 static void
@@ -1740,8 +1787,14 @@ isert_cq_tx_work(struct work_struct *work)
                        pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
                        pr_debug("TX wc.status: 0x%08x\n", wc.status);
                        pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
-                       atomic_dec(&isert_conn->post_send_buf_count);
-                       isert_cq_comp_err(tx_desc, isert_conn);
+
+                       if (wc.wr_id != ISER_FASTREG_LI_WRID) {
+                               if (tx_desc->llnode_active)
+                                       continue;
+
+                               atomic_dec(&isert_conn->post_send_buf_count);
+                               isert_cq_tx_comp_err(tx_desc, isert_conn);
+                       }
                }
        }
 
@@ -1784,7 +1837,7 @@ isert_cq_rx_work(struct work_struct *work)
                                         wc.vendor_err);
                        }
                        isert_conn->post_recv_buf_count--;
-                       isert_cq_comp_err(NULL, isert_conn);
+                       isert_cq_rx_comp_err(isert_conn);
                }
        }
 
@@ -2202,6 +2255,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
 
        if (!fr_desc->valid) {
                memset(&inv_wr, 0, sizeof(inv_wr));
+               inv_wr.wr_id = ISER_FASTREG_LI_WRID;
                inv_wr.opcode = IB_WR_LOCAL_INV;
                inv_wr.ex.invalidate_rkey = fr_desc->data_mr->rkey;
                wr = &inv_wr;
@@ -2212,6 +2266,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
 
        /* Prepare FASTREG WR */
        memset(&fr_wr, 0, sizeof(fr_wr));
+       fr_wr.wr_id = ISER_FASTREG_LI_WRID;
        fr_wr.opcode = IB_WR_FAST_REG_MR;
        fr_wr.wr.fast_reg.iova_start =
                fr_desc->data_frpl->page_list[0] + page_off;
@@ -2377,12 +2432,12 @@ isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
        isert_init_send_wr(isert_conn, isert_cmd,
                           &isert_cmd->tx_desc.send_wr, true);
 
-       atomic_inc(&isert_conn->post_send_buf_count);
+       atomic_add(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
 
        rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
        if (rc) {
                pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
-               atomic_dec(&isert_conn->post_send_buf_count);
+               atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
        }
        pr_debug("Cmd: %p posted RDMA_WRITE + Response for iSER Data READ\n",
                 isert_cmd);
@@ -2410,12 +2465,12 @@ isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
                return rc;
        }
 
-       atomic_inc(&isert_conn->post_send_buf_count);
+       atomic_add(wr->send_wr_num, &isert_conn->post_send_buf_count);
 
        rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
        if (rc) {
                pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
-               atomic_dec(&isert_conn->post_send_buf_count);
+               atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
        }
        pr_debug("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n",
                 isert_cmd);
@@ -2702,22 +2757,11 @@ isert_free_np(struct iscsi_np *np)
        kfree(isert_np);
 }
 
-static int isert_check_state(struct isert_conn *isert_conn, int state)
-{
-       int ret;
-
-       mutex_lock(&isert_conn->conn_mutex);
-       ret = (isert_conn->state == state);
-       mutex_unlock(&isert_conn->conn_mutex);
-
-       return ret;
-}
-
-static void isert_free_conn(struct iscsi_conn *conn)
+static void isert_wait_conn(struct iscsi_conn *conn)
 {
        struct isert_conn *isert_conn = conn->context;
 
-       pr_debug("isert_free_conn: Starting \n");
+       pr_debug("isert_wait_conn: Starting \n");
        /*
         * Decrement post_send_buf_count for special case when called
         * from isert_do_control_comp() -> iscsit_logout_post_handler()
@@ -2727,38 +2771,29 @@ static void isert_free_conn(struct iscsi_conn *conn)
                atomic_dec(&isert_conn->post_send_buf_count);
 
        if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
-               pr_debug("Calling rdma_disconnect from isert_free_conn\n");
+               pr_debug("Calling rdma_disconnect from isert_wait_conn\n");
                rdma_disconnect(isert_conn->conn_cm_id);
        }
        /*
         * Only wait for conn_wait_comp_err if the isert_conn made it
         * into full feature phase..
         */
-       if (isert_conn->state == ISER_CONN_UP) {
-               pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
-                        isert_conn->state);
-               mutex_unlock(&isert_conn->conn_mutex);
-
-               wait_event(isert_conn->conn_wait_comp_err,
-                         (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
-
-               wait_event(isert_conn->conn_wait,
-                         (isert_check_state(isert_conn, ISER_CONN_DOWN)));
-
-               isert_put_conn(isert_conn);
-               return;
-       }
        if (isert_conn->state == ISER_CONN_INIT) {
                mutex_unlock(&isert_conn->conn_mutex);
-               isert_put_conn(isert_conn);
                return;
        }
-       pr_debug("isert_free_conn: wait_event conn_wait %d\n",
-                isert_conn->state);
+       if (isert_conn->state == ISER_CONN_UP)
+               isert_conn->state = ISER_CONN_TERMINATING;
        mutex_unlock(&isert_conn->conn_mutex);
 
-       wait_event(isert_conn->conn_wait,
-                 (isert_check_state(isert_conn, ISER_CONN_DOWN)));
+       wait_for_completion(&isert_conn->conn_wait_comp_err);
+
+       wait_for_completion(&isert_conn->conn_wait);
+}
+
+static void isert_free_conn(struct iscsi_conn *conn)
+{
+       struct isert_conn *isert_conn = conn->context;
 
        isert_put_conn(isert_conn);
 }
@@ -2771,6 +2806,7 @@ static struct iscsit_transport iser_target_transport = {
        .iscsit_setup_np        = isert_setup_np,
        .iscsit_accept_np       = isert_accept_np,
        .iscsit_free_np         = isert_free_np,
+       .iscsit_wait_conn       = isert_wait_conn,
        .iscsit_free_conn       = isert_free_conn,
        .iscsit_get_login_rx    = isert_get_login_rx,
        .iscsit_put_login_tx    = isert_put_login_tx,
index 708a069002f3530e00002c5d1e454c1823119bb4..f6ae7f5dd4082768f3b6f0dfb36c1d45506b5eb6 100644 (file)
@@ -6,6 +6,7 @@
 
 #define ISERT_RDMA_LISTEN_BACKLOG      10
 #define ISCSI_ISER_SG_TABLESIZE                256
+#define ISER_FASTREG_LI_WRID           0xffffffffffffffffULL
 
 enum isert_desc_type {
        ISCSI_TX_CONTROL,
@@ -45,6 +46,7 @@ struct iser_tx_desc {
        struct isert_cmd *isert_cmd;
        struct llist_node *comp_llnode_batch;
        struct llist_node comp_llnode;
+       bool            llnode_active;
        struct ib_send_wr send_wr;
 } __packed;
 
@@ -116,8 +118,8 @@ struct isert_conn {
        struct isert_device     *conn_device;
        struct work_struct      conn_logout_work;
        struct mutex            conn_mutex;
-       wait_queue_head_t       conn_wait;
-       wait_queue_head_t       conn_wait_comp_err;
+       struct completion       conn_wait;
+       struct completion       conn_wait_comp_err;
        struct kref             conn_kref;
        struct list_head        conn_fr_pool;
        int                     conn_fr_pool_size;
@@ -126,7 +128,6 @@ struct isert_conn {
 #define ISERT_COMP_BATCH_COUNT 8
        int                     conn_comp_batch;
        struct llist_head       conn_comp_llist;
-       struct mutex            conn_comp_mutex;
 };
 
 #define ISERT_MAX_CQ 64
index 7a04f54ef961fda20385251413fdee4490669ef6..ef2e281b0a43b641a1dbc6f5dd7fcb9190477d24 100644 (file)
@@ -37,7 +37,6 @@ static void arizona_haptics_work(struct work_struct *work)
                                                       struct arizona_haptics,
                                                       work);
        struct arizona *arizona = haptics->arizona;
-       struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex;
        int ret;
 
        if (!haptics->arizona->dapm) {
@@ -67,13 +66,10 @@ static void arizona_haptics_work(struct work_struct *work)
                        return;
                }
 
-               mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
                ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
                                ret);
-                       mutex_unlock(dapm_mutex);
                        return;
                }
 
@@ -81,21 +77,14 @@ static void arizona_haptics_work(struct work_struct *work)
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
                                ret);
-                       mutex_unlock(dapm_mutex);
                        return;
                }
-
-               mutex_unlock(dapm_mutex);
-
        } else {
                /* This disable sequence will be a noop if already enabled */
-               mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
                ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
                                ret);
-                       mutex_unlock(dapm_mutex);
                        return;
                }
 
@@ -103,12 +92,9 @@ static void arizona_haptics_work(struct work_struct *work)
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
                                ret);
-                       mutex_unlock(dapm_mutex);
                        return;
                }
 
-               mutex_unlock(dapm_mutex);
-
                ret = regmap_update_bits(arizona->regmap,
                                         ARIZONA_HAPTICS_CONTROL_1,
                                         ARIZONA_HAP_CTRL_MASK,
@@ -155,16 +141,11 @@ static int arizona_haptics_play(struct input_dev *input, void *data,
 static void arizona_haptics_close(struct input_dev *input)
 {
        struct arizona_haptics *haptics = input_get_drvdata(input);
-       struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex;
 
        cancel_work_sync(&haptics->work);
 
-       mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
        if (haptics->arizona->dapm)
                snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");
-
-       mutex_unlock(dapm_mutex);
 }
 
 static int arizona_haptics_probe(struct platform_device *pdev)
index 8911850c94445fa5adf3b41de168293e5adf7721..1d9ab39af29f7c5d6ab2504fd2403ff725358a5d 100644 (file)
@@ -79,7 +79,6 @@
 
 #define ARM_SMMU_PTE_CONT_SIZE         (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES)
 #define ARM_SMMU_PTE_CONT_MASK         (~(ARM_SMMU_PTE_CONT_SIZE - 1))
-#define ARM_SMMU_PTE_HWTABLE_SIZE      (PTRS_PER_PTE * sizeof(pte_t))
 
 /* Stage-1 PTE */
 #define ARM_SMMU_PTE_AP_UNPRIV         (((pteval_t)1) << 6)
 #define ARM_SMMU_GR1_CBAR(n)           (0x0 + ((n) << 2))
 #define CBAR_VMID_SHIFT                        0
 #define CBAR_VMID_MASK                 0xff
+#define CBAR_S1_BPSHCFG_SHIFT          8
+#define CBAR_S1_BPSHCFG_MASK           3
+#define CBAR_S1_BPSHCFG_NSH            3
 #define CBAR_S1_MEMATTR_SHIFT          12
 #define CBAR_S1_MEMATTR_MASK           0xf
 #define CBAR_S1_MEMATTR_WB             0xf
@@ -393,7 +395,7 @@ struct arm_smmu_domain {
        struct arm_smmu_cfg             root_cfg;
        phys_addr_t                     output_mask;
 
-       struct mutex                    lock;
+       spinlock_t                      lock;
 };
 
 static DEFINE_SPINLOCK(arm_smmu_devices_lock);
@@ -632,6 +634,28 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
+static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
+                                  size_t size)
+{
+       unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+
+
+       /* Ensure new page tables are visible to the hardware walker */
+       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) {
+               dsb();
+       } else {
+               /*
+                * If the SMMU can't walk tables in the CPU caches, treat them
+                * like non-coherent DMA since we need to flush the new entries
+                * all the way out to memory. There's no possibility of
+                * recursion here as the SMMU table walker will not be wired
+                * through another SMMU.
+                */
+               dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
+                               DMA_TO_DEVICE);
+       }
+}
+
 static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
 {
        u32 reg;
@@ -650,11 +674,16 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
        if (smmu->version == 1)
              reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
 
-       /* Use the weakest memory type, so it is overridden by the pte */
-       if (stage1)
-               reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
-       else
+       /*
+        * Use the weakest shareability/memory types, so they are
+        * overridden by the ttbcr/pte.
+        */
+       if (stage1) {
+               reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) |
+                       (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+       } else {
                reg |= ARM_SMMU_CB_VMID(root_cfg) << CBAR_VMID_SHIFT;
+       }
        writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
 
        if (smmu->version > 1) {
@@ -715,6 +744,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
        }
 
        /* TTBR0 */
+       arm_smmu_flush_pgtable(smmu, root_cfg->pgd,
+                              PTRS_PER_PGD * sizeof(pgd_t));
        reg = __pa(root_cfg->pgd);
        writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
        reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
@@ -901,7 +932,7 @@ static int arm_smmu_domain_init(struct iommu_domain *domain)
                goto out_free_domain;
        smmu_domain->root_cfg.pgd = pgd;
 
-       mutex_init(&smmu_domain->lock);
+       spin_lock_init(&smmu_domain->lock);
        domain->priv = smmu_domain;
        return 0;
 
@@ -1128,6 +1159,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        struct arm_smmu_domain *smmu_domain = domain->priv;
        struct arm_smmu_device *device_smmu = dev->archdata.iommu;
        struct arm_smmu_master *master;
+       unsigned long flags;
 
        if (!device_smmu) {
                dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
@@ -1138,7 +1170,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
         * Sanity check the domain. We don't currently support domains
         * that cross between different SMMU chains.
         */
-       mutex_lock(&smmu_domain->lock);
+       spin_lock_irqsave(&smmu_domain->lock, flags);
        if (!smmu_domain->leaf_smmu) {
                /* Now that we have a master, we can finalise the domain */
                ret = arm_smmu_init_domain_context(domain, dev);
@@ -1153,7 +1185,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
                        dev_name(device_smmu->dev));
                goto err_unlock;
        }
-       mutex_unlock(&smmu_domain->lock);
+       spin_unlock_irqrestore(&smmu_domain->lock, flags);
 
        /* Looks ok, so add the device to the domain */
        master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
@@ -1163,7 +1195,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        return arm_smmu_domain_add_master(smmu_domain, master);
 
 err_unlock:
-       mutex_unlock(&smmu_domain->lock);
+       spin_unlock_irqrestore(&smmu_domain->lock, flags);
        return ret;
 }
 
@@ -1177,23 +1209,6 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
                arm_smmu_domain_remove_master(smmu_domain, master);
 }
 
-static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
-                                  size_t size)
-{
-       unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
-
-       /*
-        * If the SMMU can't walk tables in the CPU caches, treat them
-        * like non-coherent DMA since we need to flush the new entries
-        * all the way out to memory. There's no possibility of recursion
-        * here as the SMMU table walker will not be wired through another
-        * SMMU.
-        */
-       if (!(smmu->features & ARM_SMMU_FEAT_COHERENT_WALK))
-               dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
-                            DMA_TO_DEVICE);
-}
-
 static bool arm_smmu_pte_is_contiguous_range(unsigned long addr,
                                             unsigned long end)
 {
@@ -1210,12 +1225,11 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
 
        if (pmd_none(*pmd)) {
                /* Allocate a new set of tables */
-               pgtable_t table = alloc_page(PGALLOC_GFP);
+               pgtable_t table = alloc_page(GFP_ATOMIC|__GFP_ZERO);
                if (!table)
                        return -ENOMEM;
 
-               arm_smmu_flush_pgtable(smmu, page_address(table),
-                                      ARM_SMMU_PTE_HWTABLE_SIZE);
+               arm_smmu_flush_pgtable(smmu, page_address(table), PAGE_SIZE);
                if (!pgtable_page_ctor(table)) {
                        __free_page(table);
                        return -ENOMEM;
@@ -1317,9 +1331,15 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
 
 #ifndef __PAGETABLE_PMD_FOLDED
        if (pud_none(*pud)) {
-               pmd = pmd_alloc_one(NULL, addr);
+               pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
                if (!pmd)
                        return -ENOMEM;
+
+               arm_smmu_flush_pgtable(smmu, pmd, PAGE_SIZE);
+               pud_populate(NULL, pud, pmd);
+               arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
+
+               pmd += pmd_index(addr);
        } else
 #endif
                pmd = pmd_offset(pud, addr);
@@ -1328,8 +1348,6 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
                next = pmd_addr_end(addr, end);
                ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn,
                                              flags, stage);
-               pud_populate(NULL, pud, pmd);
-               arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
                phys += next - addr;
        } while (pmd++, addr = next, addr < end);
 
@@ -1346,9 +1364,15 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
 
 #ifndef __PAGETABLE_PUD_FOLDED
        if (pgd_none(*pgd)) {
-               pud = pud_alloc_one(NULL, addr);
+               pud = (pud_t *)get_zeroed_page(GFP_ATOMIC);
                if (!pud)
                        return -ENOMEM;
+
+               arm_smmu_flush_pgtable(smmu, pud, PAGE_SIZE);
+               pgd_populate(NULL, pgd, pud);
+               arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
+
+               pud += pud_index(addr);
        } else
 #endif
                pud = pud_offset(pgd, addr);
@@ -1357,8 +1381,6 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
                next = pud_addr_end(addr, end);
                ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys,
                                              flags, stage);
-               pgd_populate(NULL, pud, pgd);
-               arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
                phys += next - addr;
        } while (pud++, addr = next, addr < end);
 
@@ -1375,6 +1397,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
        struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
        pgd_t *pgd = root_cfg->pgd;
        struct arm_smmu_device *smmu = root_cfg->smmu;
+       unsigned long irqflags;
 
        if (root_cfg->cbar == CBAR_TYPE_S2_TRANS) {
                stage = 2;
@@ -1397,7 +1420,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
        if (paddr & ~output_mask)
                return -ERANGE;
 
-       mutex_lock(&smmu_domain->lock);
+       spin_lock_irqsave(&smmu_domain->lock, irqflags);
        pgd += pgd_index(iova);
        end = iova + size;
        do {
@@ -1413,11 +1436,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
        } while (pgd++, iova != end);
 
 out_unlock:
-       mutex_unlock(&smmu_domain->lock);
-
-       /* Ensure new page tables are visible to the hardware walker */
-       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
-               dsb();
+       spin_unlock_irqrestore(&smmu_domain->lock, irqflags);
 
        return ret;
 }
@@ -1987,8 +2006,10 @@ static int __init arm_smmu_init(void)
        if (!iommu_present(&platform_bus_type))
                bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
 
+#ifdef CONFIG_ARM_AMBA
        if (!iommu_present(&amba_bustype))
                bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+#endif
 
        return 0;
 }
index d97fbe4fb9b1358f0f7bea574edd6c8cd73502df..80fffba7f12dfd77dcff90d06a9783613d131827 100644 (file)
@@ -354,8 +354,8 @@ DEBUG_FOPS(mem);
                        return -ENOMEM;                                 \
        }
 
-#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600)
-#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400)
+#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 0600)
+#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 0400)
 
 static int iommu_debug_register(struct device *dev, void *data)
 {
index 92c41ab4dbfd619b5458338c3e6b6563019b150c..2cb474ad8809faa2fadaf5b08a7b06b087e73794 100644 (file)
@@ -515,7 +515,7 @@ static int meta_intc_set_affinity(struct irq_data *data,
         * one cpu (the interrupt code doesn't support it), so we just
         * pick the first cpu we find in 'cpumask'.
         */
-       cpu = cpumask_any(cpumask);
+       cpu = cpumask_any_and(cpumask, cpu_online_mask);
        thread = cpu_2_hwthread_id[cpu];
 
        metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR2(thread)), vec_addr);
index 8e94d7a3b20d277d127adf15441ea0b53879c606..c16c186d97d35f4246fa2acbd17942789922d6d7 100644 (file)
@@ -201,7 +201,7 @@ static int metag_internal_irq_set_affinity(struct irq_data *data,
         * one cpu (the interrupt code doesn't support it), so we just
         * pick the first cpu we find in 'cpumask'.
         */
-       cpu = cpumask_any(cpumask);
+       cpu = cpumask_any_and(cpumask, cpu_online_mask);
        thread = cpu_2_hwthread_id[cpu];
 
        metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR1(thread)),
index e51d40031884b1d75f12d659e2f040f391a7ad73..8e41be62812e1663df05b58f75c52ecfdc7b844f 100644 (file)
@@ -111,7 +111,8 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);
 static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
        struct irq_domain *d = irq_get_handler_data(irq);
-       struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
+
+       struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
        u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
                   gc->mask_cache;
 
@@ -123,6 +124,19 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
        }
 }
 
+/*
+ * Bridge IRQ_CAUSE is asserted regardless of IRQ_MASK register.
+ * To avoid interrupt events on stale irqs, we clear them before unmask.
+ */
+static unsigned int orion_bridge_irq_startup(struct irq_data *d)
+{
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+
+       ct->chip.irq_ack(d);
+       ct->chip.irq_unmask(d);
+       return 0;
+}
+
 static int __init orion_bridge_irq_init(struct device_node *np,
                                        struct device_node *parent)
 {
@@ -143,7 +157,7 @@ static int __init orion_bridge_irq_init(struct device_node *np,
        }
 
        ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
-                            handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+                            handle_edge_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
        if (ret) {
                pr_err("%s: unable to alloc irq domain gc\n", np->name);
                return ret;
@@ -176,12 +190,14 @@ static int __init orion_bridge_irq_init(struct device_node *np,
 
        gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;
        gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK;
+       gc->chip_types[0].chip.irq_startup = orion_bridge_irq_startup;
        gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
        gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
        gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
 
-       /* mask all interrupts */
+       /* mask and clear all interrupts */
        writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
+       writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE);
 
        irq_set_handler_data(irq, domain);
        irq_set_chained_handler(irq, orion_bridge_irq_handler);
index 9a06fe8837666036fe04afbde6d5e2adf8de6256..95ad936e60482477c1f87c0aa654fded90d06ba5 100644 (file)
@@ -254,16 +254,6 @@ config DM_THIN_PROVISIONING
        ---help---
          Provides thin provisioning and snapshots that share a data store.
 
-config DM_DEBUG_BLOCK_STACK_TRACING
-       boolean "Keep stack trace of persistent data block lock holders"
-       depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
-       select STACKTRACE
-       ---help---
-         Enable this for messages that may help debug problems with the
-         block manager locking used by thin provisioning and caching.
-
-         If unsure, say N.
-
 config DM_CACHE
        tristate "Cache target (EXPERIMENTAL)"
        depends on BLK_DEV_DM
index 1e018e986610a57ef9f82a818aa1f70a8c364e30..0e385e40909e74fcde4da4ee5d785149101ad9cb 100644 (file)
@@ -872,7 +872,7 @@ static void mq_destroy(struct dm_cache_policy *p)
 {
        struct mq_policy *mq = to_mq_policy(p);
 
-       kfree(mq->table);
+       vfree(mq->table);
        epool_exit(&mq->cache_pool);
        epool_exit(&mq->pre_cache_pool);
        kfree(mq);
@@ -1245,7 +1245,7 @@ static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
 
        mq->nr_buckets = next_power(from_cblock(cache_size) / 2, 16);
        mq->hash_bits = ffs(mq->nr_buckets) - 1;
-       mq->table = kzalloc(sizeof(*mq->table) * mq->nr_buckets, GFP_KERNEL);
+       mq->table = vzalloc(sizeof(*mq->table) * mq->nr_buckets);
        if (!mq->table)
                goto bad_alloc_table;
 
index ffd472e015caa918facaed4f65a621c0f61e58a9..074b9c8e4cf0840dd0d64014776dc297c2d82da6 100644 (file)
@@ -289,6 +289,7 @@ struct per_bio_data {
        bool tick:1;
        unsigned req_nr:2;
        struct dm_deferred_entry *all_io_entry;
+       struct dm_hook_info hook_info;
 
        /*
         * writethrough fields.  These MUST remain at the end of this
@@ -297,7 +298,6 @@ struct per_bio_data {
         */
        struct cache *cache;
        dm_cblock_t cblock;
-       struct dm_hook_info hook_info;
        struct dm_bio_details bio_details;
 };
 
@@ -671,15 +671,16 @@ static void remap_to_cache(struct cache *cache, struct bio *bio,
                           dm_cblock_t cblock)
 {
        sector_t bi_sector = bio->bi_iter.bi_sector;
+       sector_t block = from_cblock(cblock);
 
        bio->bi_bdev = cache->cache_dev->bdev;
        if (!block_size_is_power_of_two(cache))
                bio->bi_iter.bi_sector =
-                       (from_cblock(cblock) * cache->sectors_per_block) +
+                       (block * cache->sectors_per_block) +
                        sector_div(bi_sector, cache->sectors_per_block);
        else
                bio->bi_iter.bi_sector =
-                       (from_cblock(cblock) << cache->sectors_per_block_shift) |
+                       (block << cache->sectors_per_block_shift) |
                        (bi_sector & (cache->sectors_per_block - 1));
 }
 
@@ -978,12 +979,13 @@ static void issue_copy_real(struct dm_cache_migration *mg)
        int r;
        struct dm_io_region o_region, c_region;
        struct cache *cache = mg->cache;
+       sector_t cblock = from_cblock(mg->cblock);
 
        o_region.bdev = cache->origin_dev->bdev;
        o_region.count = cache->sectors_per_block;
 
        c_region.bdev = cache->cache_dev->bdev;
-       c_region.sector = from_cblock(mg->cblock) * cache->sectors_per_block;
+       c_region.sector = cblock * cache->sectors_per_block;
        c_region.count = cache->sectors_per_block;
 
        if (mg->writeback || mg->demote) {
@@ -1010,13 +1012,15 @@ static void overwrite_endio(struct bio *bio, int err)
        struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
        unsigned long flags;
 
+       dm_unhook_bio(&pb->hook_info, bio);
+
        if (err)
                mg->err = true;
 
+       mg->requeue_holder = false;
+
        spin_lock_irqsave(&cache->lock, flags);
        list_add_tail(&mg->list, &cache->completed_migrations);
-       dm_unhook_bio(&pb->hook_info, bio);
-       mg->requeue_holder = false;
        spin_unlock_irqrestore(&cache->lock, flags);
 
        wake_worker(cache);
@@ -2461,20 +2465,18 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
        bool discarded_block;
        struct dm_bio_prison_cell *cell;
        struct policy_result lookup_result;
-       struct per_bio_data *pb;
+       struct per_bio_data *pb = init_per_bio_data(bio, pb_data_size);
 
-       if (from_oblock(block) > from_oblock(cache->origin_blocks)) {
+       if (unlikely(from_oblock(block) >= from_oblock(cache->origin_blocks))) {
                /*
                 * This can only occur if the io goes to a partial block at
                 * the end of the origin device.  We don't cache these.
                 * Just remap to the origin and carry on.
                 */
-               remap_to_origin_clear_discard(cache, bio, block);
+               remap_to_origin(cache, bio);
                return DM_MAPIO_REMAPPED;
        }
 
-       pb = init_per_bio_data(bio, pb_data_size);
-
        if (bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD)) {
                defer_bio(cache, bio);
                return DM_MAPIO_SUBMITTED;
index b2b8a10e842784de5454e2639474f1a208b4b3f1..3842ac738f98ff324f5e1152f08fb546a5bb47fa 100644 (file)
@@ -201,29 +201,28 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offse
 /*
  * Functions for getting the pages from a bvec.
  */
-static void bio_get_page(struct dpages *dp,
-                 struct page **p, unsigned long *len, unsigned *offset)
+static void bio_get_page(struct dpages *dp, struct page **p,
+                        unsigned long *len, unsigned *offset)
 {
-       struct bio *bio = dp->context_ptr;
-       struct bio_vec bvec = bio_iovec(bio);
-       *p = bvec.bv_page;
-       *len = bvec.bv_len;
-       *offset = bvec.bv_offset;
+       struct bio_vec *bvec = dp->context_ptr;
+       *p = bvec->bv_page;
+       *len = bvec->bv_len - dp->context_u;
+       *offset = bvec->bv_offset + dp->context_u;
 }
 
 static void bio_next_page(struct dpages *dp)
 {
-       struct bio *bio = dp->context_ptr;
-       struct bio_vec bvec = bio_iovec(bio);
-
-       bio_advance(bio, bvec.bv_len);
+       struct bio_vec *bvec = dp->context_ptr;
+       dp->context_ptr = bvec + 1;
+       dp->context_u = 0;
 }
 
 static void bio_dp_init(struct dpages *dp, struct bio *bio)
 {
        dp->get_page = bio_get_page;
        dp->next_page = bio_next_page;
-       dp->context_ptr = bio;
+       dp->context_ptr = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
+       dp->context_u = bio->bi_iter.bi_bvec_done;
 }
 
 /*
index 6eb9dc9ef8f36c4b709df6f3b46170598964e88d..422a9fdeb53e641d97acec4793ab00747dde9b1d 100644 (file)
@@ -1626,8 +1626,11 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
        /*
         * Only pass ioctls through if the device sizes match exactly.
         */
-       if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
-               r = scsi_verify_blk_ioctl(NULL, cmd);
+       if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) {
+               int err = scsi_verify_blk_ioctl(NULL, cmd);
+               if (err)
+                       r = err;
+       }
 
        if (r == -ENOTCONN && !fatal_signal_pending(current))
                queue_work(kmultipathd, &m->process_queued_ios);
index f284e0bfb25fca869855f390f2d8d7a5519a0864..7dfdb5c746d6f31960902350c33b7457485caadb 100644 (file)
@@ -1244,6 +1244,9 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
 
                        dm_bio_restore(bd, bio);
                        bio_record->details.bi_bdev = NULL;
+
+                       atomic_inc(&bio->bi_remaining);
+
                        queue_bio(ms, bio, rw);
                        return DM_ENDIO_INCOMPLETE;
                }
index afc3d017de4c6a479f418df9197a62677539752d..d6e88178d22cff0e88fb8b21cb20558f51e8d6a1 100644 (file)
@@ -546,6 +546,9 @@ static int read_exceptions(struct pstore *ps,
                r = insert_exceptions(ps, area, callback, callback_context,
                                      &full);
 
+               if (!full)
+                       memcpy(ps->area, area, ps->store->chunk_size << SECTOR_SHIFT);
+
                dm_bufio_release(bp);
 
                dm_bufio_forget(client, chunk);
index 7da34766555284486e39a08306f88a876deeefc3..fb9efc829182d4cce55c9c8cfac1e850e65abe79 100644 (file)
@@ -76,7 +76,7 @@
 
 #define THIN_SUPERBLOCK_MAGIC 27022010
 #define THIN_SUPERBLOCK_LOCATION 0
-#define THIN_VERSION 1
+#define THIN_VERSION 2
 #define THIN_METADATA_CACHE_SIZE 64
 #define SECTOR_TO_BLOCK_SHIFT 3
 
@@ -483,7 +483,7 @@ static int __write_initial_superblock(struct dm_pool_metadata *pmd)
 
        disk_super->data_mapping_root = cpu_to_le64(pmd->root);
        disk_super->device_details_root = cpu_to_le64(pmd->details_root);
-       disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+       disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE);
        disk_super->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT);
        disk_super->data_block_size = cpu_to_le32(pmd->data_block_size);
 
@@ -651,7 +651,7 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f
 {
        int r;
 
-       pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE,
+       pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
                                          THIN_METADATA_CACHE_SIZE,
                                          THIN_MAX_CONCURRENT_LOCKS);
        if (IS_ERR(pmd->bm)) {
@@ -1489,6 +1489,23 @@ bool dm_thin_changed_this_transaction(struct dm_thin_device *td)
        return r;
 }
 
+bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd)
+{
+       bool r = false;
+       struct dm_thin_device *td, *tmp;
+
+       down_read(&pmd->root_lock);
+       list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) {
+               if (td->changed) {
+                       r = td->changed;
+                       break;
+               }
+       }
+       up_read(&pmd->root_lock);
+
+       return r;
+}
+
 bool dm_thin_aborted_changes(struct dm_thin_device *td)
 {
        bool r;
@@ -1738,3 +1755,38 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
 
        return r;
 }
+
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
+{
+       int r;
+       struct dm_block *sblock;
+       struct thin_disk_superblock *disk_super;
+
+       down_write(&pmd->root_lock);
+       pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG;
+
+       r = superblock_lock(pmd, &sblock);
+       if (r) {
+               DMERR("couldn't read superblock");
+               goto out;
+       }
+
+       disk_super = dm_block_data(sblock);
+       disk_super->flags = cpu_to_le32(pmd->flags);
+
+       dm_bm_unlock(sblock);
+out:
+       up_write(&pmd->root_lock);
+       return r;
+}
+
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd)
+{
+       bool needs_check;
+
+       down_read(&pmd->root_lock);
+       needs_check = pmd->flags & THIN_METADATA_NEEDS_CHECK_FLAG;
+       up_read(&pmd->root_lock);
+
+       return needs_check;
+}
index 9a368567632f9733f04bc0a1aebfbc3d871f13df..e3c857db195a7453d192f5f55cfb766a046a789a 100644 (file)
@@ -9,16 +9,14 @@
 
 #include "persistent-data/dm-block-manager.h"
 #include "persistent-data/dm-space-map.h"
+#include "persistent-data/dm-space-map-metadata.h"
 
-#define THIN_METADATA_BLOCK_SIZE 4096
+#define THIN_METADATA_BLOCK_SIZE DM_SM_METADATA_BLOCK_SIZE
 
 /*
  * The metadata device is currently limited in size.
- *
- * We have one block of index, which can hold 255 index entries.  Each
- * index entry contains allocation info about 16k metadata blocks.
  */
-#define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
+#define THIN_METADATA_MAX_SECTORS DM_SM_METADATA_MAX_SECTORS
 
 /*
  * A metadata device larger than 16GB triggers a warning.
 
 /*----------------------------------------------------------------*/
 
+/*
+ * Thin metadata superblock flags.
+ */
+#define THIN_METADATA_NEEDS_CHECK_FLAG (1 << 0)
+
 struct dm_pool_metadata;
 struct dm_thin_device;
 
@@ -161,6 +164,8 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block);
  */
 bool dm_thin_changed_this_transaction(struct dm_thin_device *td);
 
+bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd);
+
 bool dm_thin_aborted_changes(struct dm_thin_device *td);
 
 int dm_thin_get_highest_mapped_block(struct dm_thin_device *td,
@@ -202,6 +207,12 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
                                        dm_sm_threshold_fn fn,
                                        void *context);
 
+/*
+ * Updates the superblock immediately.
+ */
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd);
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd);
+
 /*----------------------------------------------------------------*/
 
 #endif
index faaf944597ab7669b90f3ecb85152fbcd16cbe33..be70d38745f7a7f5da51bd4ba83a29afe851b238 100644 (file)
@@ -130,10 +130,11 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
 struct dm_thin_new_mapping;
 
 /*
- * The pool runs in 3 modes.  Ordered in degraded order for comparisons.
+ * The pool runs in 4 modes.  Ordered in degraded order for comparisons.
  */
 enum pool_mode {
        PM_WRITE,               /* metadata may be changed */
+       PM_OUT_OF_DATA_SPACE,   /* metadata may be changed, though data may not be allocated */
        PM_READ_ONLY,           /* metadata may not be changed */
        PM_FAIL,                /* all I/O fails */
 };
@@ -198,7 +199,6 @@ struct pool {
 };
 
 static enum pool_mode get_pool_mode(struct pool *pool);
-static void out_of_data_space(struct pool *pool);
 static void metadata_operation_failed(struct pool *pool, const char *op, int r);
 
 /*
@@ -226,6 +226,7 @@ struct thin_c {
 
        struct pool *pool;
        struct dm_thin_device *td;
+       bool requeue_mode:1;
 };
 
 /*----------------------------------------------------------------*/
@@ -369,14 +370,18 @@ struct dm_thin_endio_hook {
        struct dm_thin_new_mapping *overwrite_mapping;
 };
 
-static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
+static void requeue_bio_list(struct thin_c *tc, struct bio_list *master)
 {
        struct bio *bio;
        struct bio_list bios;
+       unsigned long flags;
 
        bio_list_init(&bios);
+
+       spin_lock_irqsave(&tc->pool->lock, flags);
        bio_list_merge(&bios, master);
        bio_list_init(master);
+       spin_unlock_irqrestore(&tc->pool->lock, flags);
 
        while ((bio = bio_list_pop(&bios))) {
                struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
@@ -391,12 +396,26 @@ static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
 static void requeue_io(struct thin_c *tc)
 {
        struct pool *pool = tc->pool;
+
+       requeue_bio_list(tc, &pool->deferred_bios);
+       requeue_bio_list(tc, &pool->retry_on_resume_list);
+}
+
+static void error_retry_list(struct pool *pool)
+{
+       struct bio *bio;
        unsigned long flags;
+       struct bio_list bios;
+
+       bio_list_init(&bios);
 
        spin_lock_irqsave(&pool->lock, flags);
-       __requeue_bio_list(tc, &pool->deferred_bios);
-       __requeue_bio_list(tc, &pool->retry_on_resume_list);
+       bio_list_merge(&bios, &pool->retry_on_resume_list);
+       bio_list_init(&pool->retry_on_resume_list);
        spin_unlock_irqrestore(&pool->lock, flags);
+
+       while ((bio = bio_list_pop(&bios)))
+               bio_io_error(bio);
 }
 
 /*
@@ -925,13 +944,15 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks)
        }
 }
 
+static void set_pool_mode(struct pool *pool, enum pool_mode new_mode);
+
 static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
 {
        int r;
        dm_block_t free_blocks;
        struct pool *pool = tc->pool;
 
-       if (get_pool_mode(pool) != PM_WRITE)
+       if (WARN_ON(get_pool_mode(pool) != PM_WRITE))
                return -EINVAL;
 
        r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
@@ -958,7 +979,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
                }
 
                if (!free_blocks) {
-                       out_of_data_space(pool);
+                       set_pool_mode(pool, PM_OUT_OF_DATA_SPACE);
                        return -ENOSPC;
                }
        }
@@ -988,15 +1009,32 @@ static void retry_on_resume(struct bio *bio)
        spin_unlock_irqrestore(&pool->lock, flags);
 }
 
-static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+static bool should_error_unserviceable_bio(struct pool *pool)
 {
-       /*
-        * When pool is read-only, no cell locking is needed because
-        * nothing is changing.
-        */
-       WARN_ON_ONCE(get_pool_mode(pool) != PM_READ_ONLY);
+       enum pool_mode m = get_pool_mode(pool);
 
-       if (pool->pf.error_if_no_space)
+       switch (m) {
+       case PM_WRITE:
+               /* Shouldn't get here */
+               DMERR_LIMIT("bio unserviceable, yet pool is in PM_WRITE mode");
+               return true;
+
+       case PM_OUT_OF_DATA_SPACE:
+               return pool->pf.error_if_no_space;
+
+       case PM_READ_ONLY:
+       case PM_FAIL:
+               return true;
+       default:
+               /* Shouldn't get here */
+               DMERR_LIMIT("bio unserviceable, yet pool has an unknown mode");
+               return true;
+       }
+}
+
+static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+{
+       if (should_error_unserviceable_bio(pool))
                bio_io_error(bio);
        else
                retry_on_resume(bio);
@@ -1007,11 +1045,20 @@ static void retry_bios_on_resume(struct pool *pool, struct dm_bio_prison_cell *c
        struct bio *bio;
        struct bio_list bios;
 
+       if (should_error_unserviceable_bio(pool)) {
+               cell_error(pool, cell);
+               return;
+       }
+
        bio_list_init(&bios);
        cell_release(pool, cell, &bios);
 
-       while ((bio = bio_list_pop(&bios)))
-               handle_unserviceable_bio(pool, bio);
+       if (should_error_unserviceable_bio(pool))
+               while ((bio = bio_list_pop(&bios)))
+                       bio_io_error(bio);
+       else
+               while ((bio = bio_list_pop(&bios)))
+                       retry_on_resume(bio);
 }
 
 static void process_discard(struct thin_c *tc, struct bio *bio)
@@ -1296,6 +1343,11 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
        }
 }
 
+static void process_bio_success(struct thin_c *tc, struct bio *bio)
+{
+       bio_endio(bio, 0);
+}
+
 static void process_bio_fail(struct thin_c *tc, struct bio *bio)
 {
        bio_io_error(bio);
@@ -1328,6 +1380,11 @@ static void process_deferred_bios(struct pool *pool)
                struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
                struct thin_c *tc = h->tc;
 
+               if (tc->requeue_mode) {
+                       bio_endio(bio, DM_ENDIO_REQUEUE);
+                       continue;
+               }
+
                /*
                 * If we've got no free new_mapping structs, and processing
                 * this bio might require one, we pause until there are some
@@ -1357,7 +1414,8 @@ static void process_deferred_bios(struct pool *pool)
        bio_list_init(&pool->deferred_flush_bios);
        spin_unlock_irqrestore(&pool->lock, flags);
 
-       if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
+       if (bio_list_empty(&bios) &&
+           !(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool)))
                return;
 
        if (commit(pool)) {
@@ -1393,51 +1451,134 @@ static void do_waker(struct work_struct *ws)
 
 /*----------------------------------------------------------------*/
 
+struct noflush_work {
+       struct work_struct worker;
+       struct thin_c *tc;
+
+       atomic_t complete;
+       wait_queue_head_t wait;
+};
+
+static void complete_noflush_work(struct noflush_work *w)
+{
+       atomic_set(&w->complete, 1);
+       wake_up(&w->wait);
+}
+
+static void do_noflush_start(struct work_struct *ws)
+{
+       struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+       w->tc->requeue_mode = true;
+       requeue_io(w->tc);
+       complete_noflush_work(w);
+}
+
+static void do_noflush_stop(struct work_struct *ws)
+{
+       struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+       w->tc->requeue_mode = false;
+       complete_noflush_work(w);
+}
+
+static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *))
+{
+       struct noflush_work w;
+
+       INIT_WORK(&w.worker, fn);
+       w.tc = tc;
+       atomic_set(&w.complete, 0);
+       init_waitqueue_head(&w.wait);
+
+       queue_work(tc->pool->wq, &w.worker);
+
+       wait_event(w.wait, atomic_read(&w.complete));
+}
+
+/*----------------------------------------------------------------*/
+
 static enum pool_mode get_pool_mode(struct pool *pool)
 {
        return pool->pf.mode;
 }
 
+static void notify_of_pool_mode_change(struct pool *pool, const char *new_mode)
+{
+       dm_table_event(pool->ti->table);
+       DMINFO("%s: switching pool to %s mode",
+              dm_device_name(pool->pool_md), new_mode);
+}
+
 static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
 {
-       int r;
-       enum pool_mode old_mode = pool->pf.mode;
+       struct pool_c *pt = pool->ti->private;
+       bool needs_check = dm_pool_metadata_needs_check(pool->pmd);
+       enum pool_mode old_mode = get_pool_mode(pool);
+
+       /*
+        * Never allow the pool to transition to PM_WRITE mode if user
+        * intervention is required to verify metadata and data consistency.
+        */
+       if (new_mode == PM_WRITE && needs_check) {
+               DMERR("%s: unable to switch pool to write mode until repaired.",
+                     dm_device_name(pool->pool_md));
+               if (old_mode != new_mode)
+                       new_mode = old_mode;
+               else
+                       new_mode = PM_READ_ONLY;
+       }
+       /*
+        * If we were in PM_FAIL mode, rollback of metadata failed.  We're
+        * not going to recover without a thin_repair.  So we never let the
+        * pool move out of the old mode.
+        */
+       if (old_mode == PM_FAIL)
+               new_mode = old_mode;
 
        switch (new_mode) {
        case PM_FAIL:
                if (old_mode != new_mode)
-                       DMERR("%s: switching pool to failure mode",
-                             dm_device_name(pool->pool_md));
+                       notify_of_pool_mode_change(pool, "failure");
                dm_pool_metadata_read_only(pool->pmd);
                pool->process_bio = process_bio_fail;
                pool->process_discard = process_bio_fail;
                pool->process_prepared_mapping = process_prepared_mapping_fail;
                pool->process_prepared_discard = process_prepared_discard_fail;
+
+               error_retry_list(pool);
                break;
 
        case PM_READ_ONLY:
                if (old_mode != new_mode)
-                       DMERR("%s: switching pool to read-only mode",
-                             dm_device_name(pool->pool_md));
-               r = dm_pool_abort_metadata(pool->pmd);
-               if (r) {
-                       DMERR("%s: aborting transaction failed",
-                             dm_device_name(pool->pool_md));
-                       new_mode = PM_FAIL;
-                       set_pool_mode(pool, new_mode);
-               } else {
-                       dm_pool_metadata_read_only(pool->pmd);
-                       pool->process_bio = process_bio_read_only;
-                       pool->process_discard = process_discard;
-                       pool->process_prepared_mapping = process_prepared_mapping_fail;
-                       pool->process_prepared_discard = process_prepared_discard_passdown;
-               }
+                       notify_of_pool_mode_change(pool, "read-only");
+               dm_pool_metadata_read_only(pool->pmd);
+               pool->process_bio = process_bio_read_only;
+               pool->process_discard = process_bio_success;
+               pool->process_prepared_mapping = process_prepared_mapping_fail;
+               pool->process_prepared_discard = process_prepared_discard_passdown;
+
+               error_retry_list(pool);
+               break;
+
+       case PM_OUT_OF_DATA_SPACE:
+               /*
+                * Ideally we'd never hit this state; the low water mark
+                * would trigger userland to extend the pool before we
+                * completely run out of data space.  However, many small
+                * IOs to unprovisioned space can consume data space at an
+                * alarming rate.  Adjust your low water mark if you're
+                * frequently seeing this mode.
+                */
+               if (old_mode != new_mode)
+                       notify_of_pool_mode_change(pool, "out-of-data-space");
+               pool->process_bio = process_bio_read_only;
+               pool->process_discard = process_discard;
+               pool->process_prepared_mapping = process_prepared_mapping;
+               pool->process_prepared_discard = process_prepared_discard_passdown;
                break;
 
        case PM_WRITE:
                if (old_mode != new_mode)
-                       DMINFO("%s: switching pool to write mode",
-                              dm_device_name(pool->pool_md));
+                       notify_of_pool_mode_change(pool, "write");
                dm_pool_metadata_read_write(pool->pmd);
                pool->process_bio = process_bio;
                pool->process_discard = process_discard;
@@ -1447,32 +1588,35 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
        }
 
        pool->pf.mode = new_mode;
+       /*
+        * The pool mode may have changed, sync it so bind_control_target()
+        * doesn't cause an unexpected mode transition on resume.
+        */
+       pt->adjusted_pf.mode = new_mode;
 }
 
-/*
- * Rather than calling set_pool_mode directly, use these which describe the
- * reason for mode degradation.
- */
-static void out_of_data_space(struct pool *pool)
+static void abort_transaction(struct pool *pool)
 {
-       DMERR_LIMIT("%s: no free data space available.",
-                   dm_device_name(pool->pool_md));
-       set_pool_mode(pool, PM_READ_ONLY);
+       const char *dev_name = dm_device_name(pool->pool_md);
+
+       DMERR_LIMIT("%s: aborting current metadata transaction", dev_name);
+       if (dm_pool_abort_metadata(pool->pmd)) {
+               DMERR("%s: failed to abort metadata transaction", dev_name);
+               set_pool_mode(pool, PM_FAIL);
+       }
+
+       if (dm_pool_metadata_set_needs_check(pool->pmd)) {
+               DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
+               set_pool_mode(pool, PM_FAIL);
+       }
 }
 
 static void metadata_operation_failed(struct pool *pool, const char *op, int r)
 {
-       dm_block_t free_blocks;
-
        DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d",
                    dm_device_name(pool->pool_md), op, r);
 
-       if (r == -ENOSPC &&
-           !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) &&
-           !free_blocks)
-               DMERR_LIMIT("%s: no free metadata space available.",
-                           dm_device_name(pool->pool_md));
-
+       abort_transaction(pool);
        set_pool_mode(pool, PM_READ_ONLY);
 }
 
@@ -1523,6 +1667,11 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
 
        thin_hook_bio(tc, bio);
 
+       if (tc->requeue_mode) {
+               bio_endio(bio, DM_ENDIO_REQUEUE);
+               return DM_MAPIO_SUBMITTED;
+       }
+
        if (get_pool_mode(tc->pool) == PM_FAIL) {
                bio_io_error(bio);
                return DM_MAPIO_SUBMITTED;
@@ -1686,7 +1835,7 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
        /*
         * We want to make sure that a pool in PM_FAIL mode is never upgraded.
         */
-       enum pool_mode old_mode = pool->pf.mode;
+       enum pool_mode old_mode = get_pool_mode(pool);
        enum pool_mode new_mode = pt->adjusted_pf.mode;
 
        /*
@@ -1700,16 +1849,6 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
        pool->pf = pt->adjusted_pf;
        pool->low_water_blocks = pt->low_water_blocks;
 
-       /*
-        * If we were in PM_FAIL mode, rollback of metadata failed.  We're
-        * not going to recover without a thin_repair.  So we never let the
-        * pool move out of the old mode.  On the other hand a PM_READ_ONLY
-        * may have been due to a lack of metadata or data space, and may
-        * now work (ie. if the underlying devices have been resized).
-        */
-       if (old_mode == PM_FAIL)
-               new_mode = old_mode;
-
        set_pool_mode(pool, new_mode);
 
        return 0;
@@ -1999,16 +2138,27 @@ static void metadata_low_callback(void *context)
        dm_table_event(pool->ti->table);
 }
 
-static sector_t get_metadata_dev_size(struct block_device *bdev)
+static sector_t get_dev_size(struct block_device *bdev)
+{
+       return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
+}
+
+static void warn_if_metadata_device_too_big(struct block_device *bdev)
 {
-       sector_t metadata_dev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
+       sector_t metadata_dev_size = get_dev_size(bdev);
        char buffer[BDEVNAME_SIZE];
 
-       if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING) {
+       if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING)
                DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.",
                       bdevname(bdev, buffer), THIN_METADATA_MAX_SECTORS);
-               metadata_dev_size = THIN_METADATA_MAX_SECTORS_WARNING;
-       }
+}
+
+static sector_t get_metadata_dev_size(struct block_device *bdev)
+{
+       sector_t metadata_dev_size = get_dev_size(bdev);
+
+       if (metadata_dev_size > THIN_METADATA_MAX_SECTORS)
+               metadata_dev_size = THIN_METADATA_MAX_SECTORS;
 
        return metadata_dev_size;
 }
@@ -2017,7 +2167,7 @@ static dm_block_t get_metadata_dev_size_in_blocks(struct block_device *bdev)
 {
        sector_t metadata_dev_size = get_metadata_dev_size(bdev);
 
-       sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+       sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE);
 
        return metadata_dev_size;
 }
@@ -2095,12 +2245,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
                ti->error = "Error opening metadata block device";
                goto out_unlock;
        }
-
-       /*
-        * Run for the side-effect of possibly issuing a warning if the
-        * device is too big.
-        */
-       (void) get_metadata_dev_size(metadata_dev->bdev);
+       warn_if_metadata_device_too_big(metadata_dev->bdev);
 
        r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev);
        if (r) {
@@ -2246,6 +2391,12 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit)
                return -EINVAL;
 
        } else if (data_size > sb_data_size) {
+               if (dm_pool_metadata_needs_check(pool->pmd)) {
+                       DMERR("%s: unable to grow the data device until repaired.",
+                             dm_device_name(pool->pool_md));
+                       return 0;
+               }
+
                if (sb_data_size)
                        DMINFO("%s: growing the data device from %llu to %llu blocks",
                               dm_device_name(pool->pool_md),
@@ -2287,6 +2438,13 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
                return -EINVAL;
 
        } else if (metadata_dev_size > sb_metadata_dev_size) {
+               if (dm_pool_metadata_needs_check(pool->pmd)) {
+                       DMERR("%s: unable to grow the metadata device until repaired.",
+                             dm_device_name(pool->pool_md));
+                       return 0;
+               }
+
+               warn_if_metadata_device_too_big(pool->md_dev);
                DMINFO("%s: growing the metadata device from %llu to %llu blocks",
                       dm_device_name(pool->pool_md),
                       sb_metadata_dev_size, metadata_dev_size);
@@ -2673,7 +2831,9 @@ static void pool_status(struct dm_target *ti, status_type_t type,
                else
                        DMEMIT("- ");
 
-               if (pool->pf.mode == PM_READ_ONLY)
+               if (pool->pf.mode == PM_OUT_OF_DATA_SPACE)
+                       DMEMIT("out_of_data_space ");
+               else if (pool->pf.mode == PM_READ_ONLY)
                        DMEMIT("ro ");
                else
                        DMEMIT("rw ");
@@ -2787,7 +2947,7 @@ static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 10, 0},
+       .version = {1, 11, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,
@@ -2894,6 +3054,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        if (get_pool_mode(tc->pool) == PM_FAIL) {
                ti->error = "Couldn't open thin device, Pool is in fail mode";
+               r = -EINVAL;
                goto bad_thin_open;
        }
 
@@ -2905,7 +3066,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block);
        if (r)
-               goto bad_thin_open;
+               goto bad_target_max_io_len;
 
        ti->num_flush_bios = 1;
        ti->flush_supported = true;
@@ -2926,6 +3087,8 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        return 0;
 
+bad_target_max_io_len:
+       dm_pool_close_thin_device(tc->td);
 bad_thin_open:
        __pool_dec(tc->pool);
 bad_pool_lookup:
@@ -2986,10 +3149,23 @@ static int thin_endio(struct dm_target *ti, struct bio *bio, int err)
        return 0;
 }
 
-static void thin_postsuspend(struct dm_target *ti)
+static void thin_presuspend(struct dm_target *ti)
 {
+       struct thin_c *tc = ti->private;
+
        if (dm_noflush_suspending(ti))
-               requeue_io((struct thin_c *)ti->private);
+               noflush_work(tc, do_noflush_start);
+}
+
+static void thin_postsuspend(struct dm_target *ti)
+{
+       struct thin_c *tc = ti->private;
+
+       /*
+        * The dm_noflush_suspending flag has been cleared by now, so
+        * unfortunately we must always run this.
+        */
+       noflush_work(tc, do_noflush_stop);
 }
 
 /*
@@ -3074,12 +3250,13 @@ static int thin_iterate_devices(struct dm_target *ti,
 
 static struct target_type thin_target = {
        .name = "thin",
-       .version = {1, 10, 0},
+       .version = {1, 11, 0},
        .module = THIS_MODULE,
        .ctr = thin_ctr,
        .dtr = thin_dtr,
        .map = thin_map,
        .end_io = thin_endio,
+       .presuspend = thin_presuspend,
        .postsuspend = thin_postsuspend,
        .status = thin_status,
        .iterate_devices = thin_iterate_devices,
index 19b268795415b4a1eaf519001511275774a7f96e..0c2dec7aec20fd798d45b24d92156b3f85f4aae0 100644 (file)
@@ -6,3 +6,13 @@ config DM_PERSISTENT_DATA
        ---help---
         Library providing immutable on-disk data structure support for
         device-mapper targets such as the thin provisioning target.
+
+config DM_DEBUG_BLOCK_STACK_TRACING
+       boolean "Keep stack trace of persistent data block lock holders"
+       depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
+       select STACKTRACE
+       ---help---
+        Enable this for messages that may help debug problems with the
+        block manager locking used by thin provisioning and caching.
+
+        If unsure, say N.
index 536782e3bcb757427763868fbf86fcb0bd92e273..786b689bdfc7fe0c42d9a651a2369ffadcdc2382 100644 (file)
@@ -91,6 +91,69 @@ struct block_op {
        dm_block_t block;
 };
 
+struct bop_ring_buffer {
+       unsigned begin;
+       unsigned end;
+       struct block_op bops[MAX_RECURSIVE_ALLOCATIONS + 1];
+};
+
+static void brb_init(struct bop_ring_buffer *brb)
+{
+       brb->begin = 0;
+       brb->end = 0;
+}
+
+static bool brb_empty(struct bop_ring_buffer *brb)
+{
+       return brb->begin == brb->end;
+}
+
+static unsigned brb_next(struct bop_ring_buffer *brb, unsigned old)
+{
+       unsigned r = old + 1;
+       return (r >= (sizeof(brb->bops) / sizeof(*brb->bops))) ? 0 : r;
+}
+
+static int brb_push(struct bop_ring_buffer *brb,
+                   enum block_op_type type, dm_block_t b)
+{
+       struct block_op *bop;
+       unsigned next = brb_next(brb, brb->end);
+
+       /*
+        * We don't allow the last bop to be filled, this way we can
+        * differentiate between full and empty.
+        */
+       if (next == brb->begin)
+               return -ENOMEM;
+
+       bop = brb->bops + brb->end;
+       bop->type = type;
+       bop->block = b;
+
+       brb->end = next;
+
+       return 0;
+}
+
+static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result)
+{
+       struct block_op *bop;
+
+       if (brb_empty(brb))
+               return -ENODATA;
+
+       bop = brb->bops + brb->begin;
+       result->type = bop->type;
+       result->block = bop->block;
+
+       brb->begin = brb_next(brb, brb->begin);
+
+       return 0;
+}
+
+/*----------------------------------------------------------------*/
+
 struct sm_metadata {
        struct dm_space_map sm;
 
@@ -101,25 +164,20 @@ struct sm_metadata {
 
        unsigned recursion_count;
        unsigned allocated_this_transaction;
-       unsigned nr_uncommitted;
-       struct block_op uncommitted[MAX_RECURSIVE_ALLOCATIONS];
+       struct bop_ring_buffer uncommitted;
 
        struct threshold threshold;
 };
 
 static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b)
 {
-       struct block_op *op;
+       int r = brb_push(&smm->uncommitted, type, b);
 
-       if (smm->nr_uncommitted == MAX_RECURSIVE_ALLOCATIONS) {
+       if (r) {
                DMERR("too many recursive allocations");
                return -ENOMEM;
        }
 
-       op = smm->uncommitted + smm->nr_uncommitted++;
-       op->type = type;
-       op->block = b;
-
        return 0;
 }
 
@@ -158,11 +216,17 @@ static int out(struct sm_metadata *smm)
                return -ENOMEM;
        }
 
-       if (smm->recursion_count == 1 && smm->nr_uncommitted) {
-               while (smm->nr_uncommitted && !r) {
-                       smm->nr_uncommitted--;
-                       r = commit_bop(smm, smm->uncommitted +
-                                      smm->nr_uncommitted);
+       if (smm->recursion_count == 1) {
+               while (!brb_empty(&smm->uncommitted)) {
+                       struct block_op bop;
+
+                       r = brb_pop(&smm->uncommitted, &bop);
+                       if (r) {
+                               DMERR("bug in bop ring buffer");
+                               break;
+                       }
+
+                       r = commit_bop(smm, &bop);
                        if (r)
                                break;
                }
@@ -217,7 +281,8 @@ static int sm_metadata_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
 static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
                                 uint32_t *result)
 {
-       int r, i;
+       int r;
+       unsigned i;
        struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
        unsigned adjustment = 0;
 
@@ -225,8 +290,10 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
         * We may have some uncommitted adjustments to add.  This list
         * should always be really short.
         */
-       for (i = 0; i < smm->nr_uncommitted; i++) {
-               struct block_op *op = smm->uncommitted + i;
+       for (i = smm->uncommitted.begin;
+            i != smm->uncommitted.end;
+            i = brb_next(&smm->uncommitted, i)) {
+               struct block_op *op = smm->uncommitted.bops + i;
 
                if (op->block != b)
                        continue;
@@ -254,7 +321,8 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
 static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
                                              dm_block_t b, int *result)
 {
-       int r, i, adjustment = 0;
+       int r, adjustment = 0;
+       unsigned i;
        struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
        uint32_t rc;
 
@@ -262,8 +330,11 @@ static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
         * We may have some uncommitted adjustments to add.  This list
         * should always be really short.
         */
-       for (i = 0; i < smm->nr_uncommitted; i++) {
-               struct block_op *op = smm->uncommitted + i;
+       for (i = smm->uncommitted.begin;
+            i != smm->uncommitted.end;
+            i = brb_next(&smm->uncommitted, i)) {
+
+               struct block_op *op = smm->uncommitted.bops + i;
 
                if (op->block != b)
                        continue;
@@ -671,7 +742,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
        smm->begin = superblock + 1;
        smm->recursion_count = 0;
        smm->allocated_this_transaction = 0;
-       smm->nr_uncommitted = 0;
+       brb_init(&smm->uncommitted);
        threshold_init(&smm->threshold);
 
        memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm));
@@ -680,6 +751,8 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
        if (r)
                return r;
 
+       if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS)
+               nr_blocks = DM_SM_METADATA_MAX_BLOCKS;
        r = sm_ll_extend(&smm->ll, nr_blocks);
        if (r)
                return r;
@@ -713,7 +786,7 @@ int dm_sm_metadata_open(struct dm_space_map *sm,
        smm->begin = 0;
        smm->recursion_count = 0;
        smm->allocated_this_transaction = 0;
-       smm->nr_uncommitted = 0;
+       brb_init(&smm->uncommitted);
        threshold_init(&smm->threshold);
 
        memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
index 39bba0801cf2ff092a593e6ccb283f949918cc89..64df923974d86a0ad4d22d59ebdb7fd7f6ecee3f 100644 (file)
@@ -9,6 +9,17 @@
 
 #include "dm-transaction-manager.h"
 
+#define DM_SM_METADATA_BLOCK_SIZE (4096 >> SECTOR_SHIFT)
+
+/*
+ * The metadata device is currently limited in size.
+ *
+ * We have one block of index, which can hold 255 index entries.  Each
+ * index entry contains allocation info about ~16k metadata blocks.
+ */
+#define DM_SM_METADATA_MAX_BLOCKS (255 * ((1 << 14) - 64))
+#define DM_SM_METADATA_MAX_SECTORS (DM_SM_METADATA_MAX_BLOCKS * DM_SM_METADATA_BLOCK_SIZE)
+
 /*
  * Unfortunately we have to use two-phase construction due to the cycle
  * between the tm and sm.
index 13af7e50021eedd5767aa296cfe46118f55f49ac..8103e4362132a24486961bf3ac6fd80980210107 100644 (file)
@@ -53,17 +53,25 @@ static int da9055_i2c_remove(struct i2c_client *i2c)
        return 0;
 }
 
+/*
+ * DO NOT change the device Ids. The naming is intentionally specific as both
+ * the PMIC and CODEC parts of this chip are instantiated separately as I2C
+ * devices (both have configurable I2C addresses, and are to all intents and
+ * purposes separate). As a result there are specific DA9055 ids for PMIC
+ * and CODEC, which must be different to operate together.
+ */
 static struct i2c_device_id da9055_i2c_id[] = {
-       {"da9055", 0},
+       {"da9055-pmic", 0},
        { }
 };
+MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
 
 static struct i2c_driver da9055_i2c_driver = {
        .probe = da9055_i2c_probe,
        .remove = da9055_i2c_remove,
        .id_table = da9055_i2c_id,
        .driver = {
-               .name = "da9055",
+               .name = "da9055-pmic",
                .owner = THIS_MODULE,
        },
 };
index ac514fb2b8779ef6a1b7395bcd6c26cc45aefdc2..71aa14a6bfbbb4ffd061aeb91df739fc70684446 100644 (file)
@@ -173,6 +173,7 @@ static const struct i2c_device_id max14577_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
 
+#ifdef CONFIG_PM_SLEEP
 static int max14577_suspend(struct device *dev)
 {
        struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
@@ -208,6 +209,7 @@ static int max14577_resume(struct device *dev)
 
        return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static struct of_device_id max14577_dt_match[] = {
        { .compatible = "maxim,max14577", },
index be88a3bf7b857a5b19f7e9d95b1be42c7e58b2d3..5adede0fb04c8c5a82f7804d3138ab1f7a74f334 100644 (file)
@@ -164,15 +164,15 @@ static struct max8997_platform_data *max8997_i2c_parse_dt_pdata(
        return pd;
 }
 
-static inline int max8997_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long max8997_i2c_get_driver_data(struct i2c_client *i2c,
                                                const struct i2c_device_id *id)
 {
        if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
                const struct of_device_id *match;
                match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node);
-               return (int)match->data;
+               return (unsigned long)match->data;
        }
-       return (int)id->driver_data;
+       return id->driver_data;
 }
 
 static int max8997_i2c_probe(struct i2c_client *i2c,
index 612ca404e1502d6c736eaf239d9b721e522664f9..5d5e186b5d8bbbfed035725480fb85dc52a0fdb4 100644 (file)
@@ -169,16 +169,16 @@ static struct max8998_platform_data *max8998_i2c_parse_dt_pdata(
        return pd;
 }
 
-static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long max8998_i2c_get_driver_data(struct i2c_client *i2c,
                                                const struct i2c_device_id *id)
 {
        if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
                const struct of_device_id *match;
                match = of_match_node(max8998_dt_match, i2c->dev.of_node);
-               return (int)(long)match->data;
+               return (unsigned long)match->data;
        }
 
-       return (int)id->driver_data;
+       return id->driver_data;
 }
 
 static int max8998_i2c_probe(struct i2c_client *i2c,
index a139798b806546b751b37f22e4d3e8044f3e2422..714e2135210ec2ddc989efcd44f3e800b80f5bcf 100644 (file)
@@ -315,6 +315,7 @@ static int sec_pmic_remove(struct i2c_client *i2c)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int sec_pmic_suspend(struct device *dev)
 {
        struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
@@ -349,6 +350,7 @@ static int sec_pmic_resume(struct device *dev)
 
        return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
 
index 966cf65c5c363f63d907048fe4bb31b3d30bbbac..3cc4c7084b9244dcc18dd42a7ab77a3550e59ddb 100644 (file)
@@ -158,7 +158,7 @@ static int tps65217_probe(struct i2c_client *client,
 {
        struct tps65217 *tps;
        unsigned int version;
-       unsigned int chip_id = ids->driver_data;
+       unsigned long chip_id = ids->driver_data;
        const struct of_device_id *match;
        bool status_off = false;
        int ret;
@@ -170,7 +170,7 @@ static int tps65217_probe(struct i2c_client *client,
                                "Failed to find matching dt id\n");
                        return -EINVAL;
                }
-               chip_id = (unsigned int)(unsigned long)match->data;
+               chip_id = (unsigned long)match->data;
                status_off = of_property_read_bool(client->dev.of_node,
                                        "ti,pmic-shutdown-controller");
        }
index ba04f1bc70eb52988ce27b5f4e45195e8b216b82..e6fab94e2c8a0fb1eed8df339833e36f2dd7c38b 100644 (file)
@@ -636,7 +636,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
        if (i2c->dev.of_node) {
                of_id = of_match_device(wm8994_of_match, &i2c->dev);
                if (of_id)
-                       wm8994->type = (int)of_id->data;
+                       wm8994->type = (enum wm8994_type)of_id->data;
        } else {
                wm8994->type = id->driver_data;
        }
index 9b809cfc289924912b92a00d826831fbb46433ec..89a557972d1b926abe915760366d6602c1efa0cf 100644 (file)
@@ -666,7 +666,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
                goto err;
 
        cb->fop_type = MEI_FOP_READ;
-       cl->read_cb = cb;
        if (dev->hbuf_is_ready) {
                dev->hbuf_is_ready = false;
                if (mei_hbm_cl_flow_control_req(dev, cl)) {
@@ -678,6 +677,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
        } else {
                list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
        }
+
+       cl->read_cb = cb;
+
        return rets;
 err:
        mei_io_cb_free(cb);
index b9e2000969f025894be4bcae2c6950d699ded3a9..95c894482fddf443d4516ffad39c54adda5be754 100644 (file)
@@ -240,7 +240,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
 
        nid = cpu_to_node(cpu);
        page = alloc_pages_exact_node(nid,
-                                     GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                                     GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                      pg_order);
        if (page == NULL) {
                dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
index 59eba5d2c68574fae787d36d2bd9e5ed29eb9f25..9715a7ba164a042abbba49fd842e9400a677d6fe 100644 (file)
@@ -1584,7 +1584,7 @@ read_retry:
                        }
 
                        if (mtd->ecc_stats.failed - ecc_failures) {
-                               if (retry_mode + 1 <= chip->read_retries) {
+                               if (retry_mode + 1 < chip->read_retries) {
                                        retry_mode++;
                                        ret = nand_setup_read_retry(mtd,
                                                        retry_mode);
index ef4190a02b7bd591af7c97be8ee1e3caecf6f83c..bf642ceef68172b4575d8e9d3263320e0fc7095a 100644 (file)
@@ -1633,6 +1633,7 @@ static int omap_nand_probe(struct platform_device *pdev)
        int                             i;
        dma_cap_mask_t                  mask;
        unsigned                        sig;
+       unsigned                        oob_index;
        struct resource                 *res;
        struct mtd_part_parser_data     ppdata = {};
 
@@ -1826,11 +1827,14 @@ static int omap_nand_probe(struct platform_device *pdev)
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
                if (nand_chip->options & NAND_BUSWIDTH_16)
-                       ecclayout->eccpos[0]    = BADBLOCK_MARKER_LENGTH;
+                       oob_index               = BADBLOCK_MARKER_LENGTH;
                else
-                       ecclayout->eccpos[0]    = 1;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+                       oob_index               = 1;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+                       ecclayout->eccpos[i]    = oob_index;
+               /* no reserved-marker in ecclayout for this ecc-scheme */
+               ecclayout->oobfree->offset      =
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                break;
 
        case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
@@ -1847,9 +1851,15 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
-               ecclayout->eccpos[0]            = BADBLOCK_MARKER_LENGTH;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+               oob_index                       = BADBLOCK_MARKER_LENGTH;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
+                       ecclayout->eccpos[i] = oob_index;
+                       if (((i + 1) % nand_chip->ecc.bytes) == 0)
+                               oob_index++;
+               }
+               /* include reserved-marker in ecclayout->oobfree calculation */
+               ecclayout->oobfree->offset      = 1 +
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* software bch library is used for locating errors */
                nand_chip->ecc.priv             = nand_bch_init(mtd,
                                                        nand_chip->ecc.size,
@@ -1883,9 +1893,12 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
-               ecclayout->eccpos[0]            = BADBLOCK_MARKER_LENGTH;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+               oob_index                       = BADBLOCK_MARKER_LENGTH;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+                       ecclayout->eccpos[i]    = oob_index;
+               /* reserved marker already included in ecclayout->eccbytes */
+               ecclayout->oobfree->offset      =
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* This ECC scheme requires ELM H/W block */
                if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
                        pr_err("nand: error: could not initialize ELM\n");
@@ -1913,9 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
-               ecclayout->eccpos[0]            = BADBLOCK_MARKER_LENGTH;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+               oob_index                       = BADBLOCK_MARKER_LENGTH;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
+                       ecclayout->eccpos[i] = oob_index;
+                       if (((i + 1) % nand_chip->ecc.bytes) == 0)
+                               oob_index++;
+               }
+               /* include reserved-marker in ecclayout->oobfree calculation */
+               ecclayout->oobfree->offset      = 1 +
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* software bch library is used for locating errors */
                nand_chip->ecc.priv             = nand_bch_init(mtd,
                                                        nand_chip->ecc.size,
@@ -1956,9 +1975,12 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
-               ecclayout->eccpos[0]            = BADBLOCK_MARKER_LENGTH;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+               oob_index                       = BADBLOCK_MARKER_LENGTH;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+                       ecclayout->eccpos[i]    = oob_index;
+               /* reserved marker already included in ecclayout->eccbytes */
+               ecclayout->oobfree->offset      =
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                break;
 #else
                pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
@@ -1972,11 +1994,8 @@ static int omap_nand_probe(struct platform_device *pdev)
                goto return_error;
        }
 
-       /* populate remaining ECC layout data */
-       ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH +
-                                                       ecclayout->eccbytes);
-       for (i = 1; i < ecclayout->eccbytes; i++)
-               ecclayout->eccpos[i] = ecclayout->eccpos[0] + i;
+       /* all OOB bytes from oobfree->offset till end off OOB are free */
+       ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
        /* check if NAND device's OOB is enough to store ECC signatures */
        if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
                pr_err("not enough OOB bytes required = %d, available=%d\n",
index ead861307b3c57aac13bbb187a958a8910062904..c5dad652614d747df33477dbd414c472572aefe5 100644 (file)
@@ -463,8 +463,8 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,
                                }
                        }
                        if (found_orphan) {
-                               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                                list_del(&tmp_aeb->u.list);
+                               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                        }
 
                        new_aeb = kmem_cache_alloc(ai->aeb_slab_cache,
@@ -846,16 +846,16 @@ fail_bad:
        ret = UBI_BAD_FASTMAP;
 fail:
        list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) {
-               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                list_del(&tmp_aeb->u.list);
+               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
        }
        list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &eba_orphans, u.list) {
-               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                list_del(&tmp_aeb->u.list);
+               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
        }
        list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) {
-               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                list_del(&tmp_aeb->u.list);
+               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
        }
 
        return ret;
index 494b888a65681bde29911f13bea5ab02ed1c32d2..89402c3b64f8406ebc0e81a7d79fb341fa57df3d 100644 (file)
@@ -177,11 +177,6 @@ config NETCONSOLE_DYNAMIC
 config NETPOLL
        def_bool NETCONSOLE
 
-config NETPOLL_TRAP
-       bool "Netpoll traffic trapping"
-       default n
-       depends on NETPOLL
-
 config NET_POLL_CONTROLLER
        def_bool NETPOLL
 
index f04f3625e9440804bdb06cd6445cc1eed628d56b..dee2a84a2929e1380ac679e3785323781824faf2 100644 (file)
@@ -181,7 +181,7 @@ static inline int __agg_has_partner(struct aggregator *agg)
  */
 static inline void __disable_port(struct port *port)
 {
-       bond_set_slave_inactive_flags(port->slave);
+       bond_set_slave_inactive_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
 }
 
 /**
@@ -193,7 +193,7 @@ static inline void __enable_port(struct port *port)
        struct slave *slave = port->slave;
 
        if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev))
-               bond_set_slave_active_flags(slave);
+               bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_LATER);
 }
 
 /**
@@ -2063,6 +2063,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        struct list_head *iter;
        struct slave *slave;
        struct port *port;
+       bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
 
        read_lock(&bond->lock);
        rcu_read_lock();
@@ -2120,8 +2121,19 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        }
 
 re_arm:
+       bond_for_each_slave_rcu(bond, slave, iter) {
+               if (slave->should_notify) {
+                       should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+                       break;
+               }
+       }
        rcu_read_unlock();
        read_unlock(&bond->lock);
+
+       if (should_notify_rtnl && rtnl_trylock()) {
+               bond_slave_state_notify(bond);
+               rtnl_unlock();
+       }
        queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
 }
 
@@ -2467,7 +2479,7 @@ out:
        return NETDEV_TX_OK;
 err_free:
        /* no suitable interface, frame not sent */
-       kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        goto out;
 }
 
index aaeeacf767f24e128ff75a5c54fb25ef4bcb8a58..9f69e818b0009db7881b3f8c862393836e5a604b 100644 (file)
@@ -722,7 +722,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
                        client_info->ntt = 0;
                }
 
-               if (!vlan_get_tag(skb, &client_info->vlan_id))
+               if (vlan_get_tag(skb, &client_info->vlan_id))
                        client_info->vlan_id = 0;
 
                if (!client_info->assigned) {
@@ -1005,7 +1005,7 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[],
        memset(&pkt, 0, size);
        ether_addr_copy(pkt.mac_dst, mac_addr);
        ether_addr_copy(pkt.mac_src, mac_addr);
-       pkt.type = cpu_to_be16(ETH_P_LOOP);
+       pkt.type = cpu_to_be16(ETH_P_LOOPBACK);
 
        skb = dev_alloc_skb(size);
        if (!skb)
@@ -1464,7 +1464,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
        }
 
        /* no suitable interface, frame not sent */
-       kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 out:
        return NETDEV_TX_OK;
 }
index 12861e37d526a4af9b44411e86be6728d887ae26..e717db301d4659b5dc4cd0255e57bd2d5157435a 100644 (file)
@@ -829,21 +829,25 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
        if (bond_is_lb(bond)) {
                bond_alb_handle_active_change(bond, new_active);
                if (old_active)
-                       bond_set_slave_inactive_flags(old_active);
+                       bond_set_slave_inactive_flags(old_active,
+                                                     BOND_SLAVE_NOTIFY_NOW);
                if (new_active)
-                       bond_set_slave_active_flags(new_active);
+                       bond_set_slave_active_flags(new_active,
+                                                   BOND_SLAVE_NOTIFY_NOW);
        } else {
                rcu_assign_pointer(bond->curr_active_slave, new_active);
        }
 
        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
                if (old_active)
-                       bond_set_slave_inactive_flags(old_active);
+                       bond_set_slave_inactive_flags(old_active,
+                                                     BOND_SLAVE_NOTIFY_NOW);
 
                if (new_active) {
                        bool should_notify_peers = false;
 
-                       bond_set_slave_active_flags(new_active);
+                       bond_set_slave_active_flags(new_active,
+                                                   BOND_SLAVE_NOTIFY_NOW);
 
                        if (bond->params.fail_over_mac)
                                bond_do_fail_over_mac(bond, new_active,
@@ -1182,6 +1186,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                return -EBUSY;
        }
 
+       if (bond_dev == slave_dev) {
+               pr_err("%s: cannot enslave bond to itself.\n", bond_dev->name);
+               return -EPERM;
+       }
+
        /* vlan challenged mutual exclusion */
        /* no need to lock since we're protected by rtnl_lock */
        if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
@@ -1451,14 +1460,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        switch (bond->params.mode) {
        case BOND_MODE_ACTIVEBACKUP:
-               bond_set_slave_inactive_flags(new_slave);
+               bond_set_slave_inactive_flags(new_slave,
+                                             BOND_SLAVE_NOTIFY_NOW);
                break;
        case BOND_MODE_8023AD:
                /* in 802.3ad mode, the internal mechanism
                 * will activate the slaves in the selected
                 * aggregator
                 */
-               bond_set_slave_inactive_flags(new_slave);
+               bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
                /* if this is the first slave */
                if (!prev_slave) {
                        SLAVE_AD_INFO(new_slave).id = 1;
@@ -1476,7 +1486,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        case BOND_MODE_TLB:
        case BOND_MODE_ALB:
                bond_set_active_slave(new_slave);
-               bond_set_slave_inactive_flags(new_slave);
+               bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
                break;
        default:
                pr_debug("This slave is always active in trunk mode\n");
@@ -1641,9 +1651,6 @@ static int __bond_release_one(struct net_device *bond_dev,
                return -EINVAL;
        }
 
-       /* release the slave from its bond */
-       bond->slave_cnt--;
-
        bond_sysfs_slave_del(slave);
 
        bond_upper_dev_unlink(bond_dev, slave_dev);
@@ -1725,6 +1732,7 @@ static int __bond_release_one(struct net_device *bond_dev,
 
        unblock_netpoll_tx();
        synchronize_rcu();
+       bond->slave_cnt--;
 
        if (!bond_has_slaves(bond)) {
                call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
@@ -1998,7 +2006,8 @@ static void bond_miimon_commit(struct bonding *bond)
 
                        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP ||
                            bond->params.mode == BOND_MODE_8023AD)
-                               bond_set_slave_inactive_flags(slave);
+                               bond_set_slave_inactive_flags(slave,
+                                                             BOND_SLAVE_NOTIFY_NOW);
 
                        pr_info("%s: link status definitely down for interface %s, disabling it\n",
                                bond->dev->name, slave->dev->name);
@@ -2553,7 +2562,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
                                slave->link = BOND_LINK_UP;
                                if (bond->current_arp_slave) {
                                        bond_set_slave_inactive_flags(
-                                               bond->current_arp_slave);
+                                               bond->current_arp_slave,
+                                               BOND_SLAVE_NOTIFY_NOW);
                                        bond->current_arp_slave = NULL;
                                }
 
@@ -2573,7 +2583,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
                                slave->link_failure_count++;
 
                        slave->link = BOND_LINK_DOWN;
-                       bond_set_slave_inactive_flags(slave);
+                       bond_set_slave_inactive_flags(slave,
+                                                     BOND_SLAVE_NOTIFY_NOW);
 
                        pr_info("%s: link status definitely down for interface %s, disabling it\n",
                                bond->dev->name, slave->dev->name);
@@ -2606,17 +2617,17 @@ do_failover:
 
 /*
  * Send ARP probes for active-backup mode ARP monitor.
+ *
+ * Called with rcu_read_lock hold.
  */
 static bool bond_ab_arp_probe(struct bonding *bond)
 {
        struct slave *slave, *before = NULL, *new_slave = NULL,
-                    *curr_arp_slave, *curr_active_slave;
+                    *curr_arp_slave = rcu_dereference(bond->current_arp_slave),
+                    *curr_active_slave = rcu_dereference(bond->curr_active_slave);
        struct list_head *iter;
        bool found = false;
-
-       rcu_read_lock();
-       curr_arp_slave = rcu_dereference(bond->current_arp_slave);
-       curr_active_slave = rcu_dereference(bond->curr_active_slave);
+       bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
 
        if (curr_arp_slave && curr_active_slave)
                pr_info("PROBE: c_arp %s && cas %s BAD\n",
@@ -2625,32 +2636,23 @@ static bool bond_ab_arp_probe(struct bonding *bond)
 
        if (curr_active_slave) {
                bond_arp_send_all(bond, curr_active_slave);
-               rcu_read_unlock();
-               return true;
+               return should_notify_rtnl;
        }
-       rcu_read_unlock();
 
        /* if we don't have a curr_active_slave, search for the next available
         * backup slave from the current_arp_slave and make it the candidate
         * for becoming the curr_active_slave
         */
 
-       if (!rtnl_trylock())
-               return false;
-       /* curr_arp_slave might have gone away */
-       curr_arp_slave = ACCESS_ONCE(bond->current_arp_slave);
-
        if (!curr_arp_slave) {
-               curr_arp_slave = bond_first_slave(bond);
-               if (!curr_arp_slave) {
-                       rtnl_unlock();
-                       return true;
-               }
+               curr_arp_slave = bond_first_slave_rcu(bond);
+               if (!curr_arp_slave)
+                       return should_notify_rtnl;
        }
 
-       bond_set_slave_inactive_flags(curr_arp_slave);
+       bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_LATER);
 
-       bond_for_each_slave(bond, slave, iter) {
+       bond_for_each_slave_rcu(bond, slave, iter) {
                if (!found && !before && IS_UP(slave->dev))
                        before = slave;
 
@@ -2668,7 +2670,8 @@ static bool bond_ab_arp_probe(struct bonding *bond)
                        if (slave->link_failure_count < UINT_MAX)
                                slave->link_failure_count++;
 
-                       bond_set_slave_inactive_flags(slave);
+                       bond_set_slave_inactive_flags(slave,
+                                                     BOND_SLAVE_NOTIFY_LATER);
 
                        pr_info("%s: backup interface %s is now down\n",
                                bond->dev->name, slave->dev->name);
@@ -2680,26 +2683,31 @@ static bool bond_ab_arp_probe(struct bonding *bond)
        if (!new_slave && before)
                new_slave = before;
 
-       if (!new_slave) {
-               rtnl_unlock();
-               return true;
-       }
+       if (!new_slave)
+               goto check_state;
 
        new_slave->link = BOND_LINK_BACK;
-       bond_set_slave_active_flags(new_slave);
+       bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER);
        bond_arp_send_all(bond, new_slave);
        new_slave->last_link_up = jiffies;
        rcu_assign_pointer(bond->current_arp_slave, new_slave);
-       rtnl_unlock();
 
-       return true;
+check_state:
+       bond_for_each_slave_rcu(bond, slave, iter) {
+               if (slave->should_notify) {
+                       should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+                       break;
+               }
+       }
+       return should_notify_rtnl;
 }
 
 static void bond_activebackup_arp_mon(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            arp_work.work);
-       bool should_notify_peers = false, should_commit = false;
+       bool should_notify_peers = false;
+       bool should_notify_rtnl = false;
        int delta_in_ticks;
 
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
@@ -2708,11 +2716,12 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
                goto re_arm;
 
        rcu_read_lock();
+
        should_notify_peers = bond_should_notify_peers(bond);
-       should_commit = bond_ab_arp_inspect(bond);
-       rcu_read_unlock();
 
-       if (should_commit) {
+       if (bond_ab_arp_inspect(bond)) {
+               rcu_read_unlock();
+
                /* Race avoidance with bond_close flush of workqueue */
                if (!rtnl_trylock()) {
                        delta_in_ticks = 1;
@@ -2721,23 +2730,28 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
                }
 
                bond_ab_arp_commit(bond);
+
                rtnl_unlock();
+               rcu_read_lock();
        }
 
-       if (!bond_ab_arp_probe(bond)) {
-               /* rtnl locking failed, re-arm */
-               delta_in_ticks = 1;
-               should_notify_peers = false;
-       }
+       should_notify_rtnl = bond_ab_arp_probe(bond);
+       rcu_read_unlock();
 
 re_arm:
        if (bond->params.arp_interval)
                queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
 
-       if (should_notify_peers) {
+       if (should_notify_peers || should_notify_rtnl) {
                if (!rtnl_trylock())
                        return;
-               call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev);
+
+               if (should_notify_peers)
+                       call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
+                                                bond->dev);
+               if (should_notify_rtnl)
+                       bond_slave_state_notify(bond);
+
                rtnl_unlock();
        }
 }
@@ -3036,9 +3050,11 @@ static int bond_open(struct net_device *bond_dev)
                bond_for_each_slave(bond, slave, iter) {
                        if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
                                && (slave != bond->curr_active_slave)) {
-                               bond_set_slave_inactive_flags(slave);
+                               bond_set_slave_inactive_flags(slave,
+                                                             BOND_SLAVE_NOTIFY_NOW);
                        } else {
-                               bond_set_slave_active_flags(slave);
+                               bond_set_slave_active_flags(slave,
+                                                           BOND_SLAVE_NOTIFY_NOW);
                        }
                }
                read_unlock(&bond->curr_slave_lock);
@@ -3532,7 +3548,7 @@ static void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int sl
                }
        }
        /* no slave that can tx has been found */
-       kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 }
 
 /**
@@ -3608,7 +3624,7 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
        if (slave)
                bond_dev_queue_xmit(bond, skb, slave->dev);
        else
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
@@ -3651,7 +3667,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
        if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP)
                bond_dev_queue_xmit(bond, skb, slave->dev);
        else
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
@@ -3738,7 +3754,7 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev
                pr_err("%s: Error: Unknown bonding mode %d\n",
                       dev->name, bond->params.mode);
                WARN_ON_ONCE(1);
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 }
@@ -3759,7 +3775,7 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (bond_has_slaves(bond))
                ret = __bond_start_xmit(skb, dev);
        else
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
        rcu_read_unlock();
 
        return ret;
@@ -3931,56 +3947,11 @@ static void bond_uninit(struct net_device *bond_dev)
 
 /*------------------------- Module initialization ---------------------------*/
 
-int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl)
-{
-       int i;
-
-       for (i = 0; tbl[i].modename; i++)
-               if (mode == tbl[i].mode)
-                       return tbl[i].mode;
-
-       return -1;
-}
-
-static int bond_parm_tbl_lookup_name(const char *modename,
-                                    const struct bond_parm_tbl *tbl)
-{
-       int i;
-
-       for (i = 0; tbl[i].modename; i++)
-               if (strcmp(modename, tbl[i].modename) == 0)
-                       return tbl[i].mode;
-
-       return -1;
-}
-
-/*
- * Convert string input module parms.  Accept either the
- * number of the mode or its string name.  A bit complicated because
- * some mode names are substrings of other names, and calls from sysfs
- * may have whitespace in the name (trailing newlines, for example).
- */
-int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
-{
-       int modeint;
-       char *p, modestr[BOND_MAX_MODENAME_LEN + 1];
-
-       for (p = (char *)buf; *p; p++)
-               if (!(isdigit(*p) || isspace(*p)))
-                       break;
-
-       if (*p && sscanf(buf, "%20s", modestr) != 0)
-               return bond_parm_tbl_lookup_name(modestr, tbl);
-       else if (sscanf(buf, "%d", &modeint) != 0)
-               return bond_parm_tbl_lookup(modeint, tbl);
-
-       return -1;
-}
-
 static int bond_check_params(struct bond_params *params)
 {
        int arp_validate_value, fail_over_mac_value, primary_reselect_value, i;
-       struct bond_opt_value newval, *valptr;
+       struct bond_opt_value newval;
+       const struct bond_opt_value *valptr;
        int arp_all_targets_value;
 
        /*
index 20659b114f24c9b30ff62c1f5518ea9e0680ff8e..f847e165d252fb2a4528fe396b2c4f0553e81ac3 100644 (file)
@@ -199,7 +199,7 @@ static int bond_changelink(struct net_device *bond_dev,
                nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
                        __be32 target = nla_get_be32(attr);
 
-                       bond_opt_initval(&newval, target);
+                       bond_opt_initval(&newval, (__force u64)target);
                        err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
                                             &newval);
                        if (err)
index 23f365510b58b75545f43dc47cb26d0bbc53a647..6e6b09359ec35479d604db91e28b5c91c5a95708 100644 (file)
 #include <linux/inet.h>
 #include "bonding.h"
 
-static struct bond_opt_value bond_mode_tbl[] = {
+static int bond_option_active_slave_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval);
+static int bond_option_miimon_set(struct bonding *bond,
+                                 const struct bond_opt_value *newval);
+static int bond_option_updelay_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval);
+static int bond_option_downdelay_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval);
+static int bond_option_use_carrier_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval);
+static int bond_option_arp_interval_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval);
+static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
+static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
+static int bond_option_arp_ip_targets_set(struct bonding *bond,
+                                         const struct bond_opt_value *newval);
+static int bond_option_arp_validate_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval);
+static int bond_option_arp_all_targets_set(struct bonding *bond,
+                                          const struct bond_opt_value *newval);
+static int bond_option_primary_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval);
+static int bond_option_primary_reselect_set(struct bonding *bond,
+                                           const struct bond_opt_value *newval);
+static int bond_option_fail_over_mac_set(struct bonding *bond,
+                                        const struct bond_opt_value *newval);
+static int bond_option_xmit_hash_policy_set(struct bonding *bond,
+                                           const struct bond_opt_value *newval);
+static int bond_option_resend_igmp_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval);
+static int bond_option_num_peer_notif_set(struct bonding *bond,
+                                         const struct bond_opt_value *newval);
+static int bond_option_all_slaves_active_set(struct bonding *bond,
+                                            const struct bond_opt_value *newval);
+static int bond_option_min_links_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval);
+static int bond_option_lp_interval_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval);
+static int bond_option_pps_set(struct bonding *bond,
+                              const struct bond_opt_value *newval);
+static int bond_option_lacp_rate_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval);
+static int bond_option_ad_select_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval);
+static int bond_option_queue_id_set(struct bonding *bond,
+                                   const struct bond_opt_value *newval);
+static int bond_option_mode_set(struct bonding *bond,
+                               const struct bond_opt_value *newval);
+static int bond_option_slaves_set(struct bonding *bond,
+                                 const struct bond_opt_value *newval);
+
+
+static const struct bond_opt_value bond_mode_tbl[] = {
        { "balance-rr",    BOND_MODE_ROUNDROBIN,   BOND_VALFLAG_DEFAULT},
        { "active-backup", BOND_MODE_ACTIVEBACKUP, 0},
        { "balance-xor",   BOND_MODE_XOR,          0},
@@ -31,13 +83,13 @@ static struct bond_opt_value bond_mode_tbl[] = {
        { NULL,            -1,                     0},
 };
 
-static struct bond_opt_value bond_pps_tbl[] = {
+static const struct bond_opt_value bond_pps_tbl[] = {
        { "default", 1,         BOND_VALFLAG_DEFAULT},
        { "maxval",  USHRT_MAX, BOND_VALFLAG_MAX},
        { NULL,      -1,        0},
 };
 
-static struct bond_opt_value bond_xmit_hashtype_tbl[] = {
+static const struct bond_opt_value bond_xmit_hashtype_tbl[] = {
        { "layer2",   BOND_XMIT_POLICY_LAYER2, BOND_VALFLAG_DEFAULT},
        { "layer3+4", BOND_XMIT_POLICY_LAYER34, 0},
        { "layer2+3", BOND_XMIT_POLICY_LAYER23, 0},
@@ -46,7 +98,7 @@ static struct bond_opt_value bond_xmit_hashtype_tbl[] = {
        { NULL,       -1,                       0},
 };
 
-static struct bond_opt_value bond_arp_validate_tbl[] = {
+static const struct bond_opt_value bond_arp_validate_tbl[] = {
        { "none",               BOND_ARP_VALIDATE_NONE,         BOND_VALFLAG_DEFAULT},
        { "active",             BOND_ARP_VALIDATE_ACTIVE,       0},
        { "backup",             BOND_ARP_VALIDATE_BACKUP,       0},
@@ -57,76 +109,77 @@ static struct bond_opt_value bond_arp_validate_tbl[] = {
        { NULL,                 -1,                             0},
 };
 
-static struct bond_opt_value bond_arp_all_targets_tbl[] = {
+static const struct bond_opt_value bond_arp_all_targets_tbl[] = {
        { "any", BOND_ARP_TARGETS_ANY, BOND_VALFLAG_DEFAULT},
        { "all", BOND_ARP_TARGETS_ALL, 0},
        { NULL,  -1,                   0},
 };
 
-static struct bond_opt_value bond_fail_over_mac_tbl[] = {
+static const struct bond_opt_value bond_fail_over_mac_tbl[] = {
        { "none",   BOND_FOM_NONE,   BOND_VALFLAG_DEFAULT},
        { "active", BOND_FOM_ACTIVE, 0},
        { "follow", BOND_FOM_FOLLOW, 0},
        { NULL,     -1,              0},
 };
 
-static struct bond_opt_value bond_intmax_tbl[] = {
+static const struct bond_opt_value bond_intmax_tbl[] = {
        { "off",     0,       BOND_VALFLAG_DEFAULT},
        { "maxval",  INT_MAX, BOND_VALFLAG_MAX},
 };
 
-static struct bond_opt_value bond_lacp_rate_tbl[] = {
+static const struct bond_opt_value bond_lacp_rate_tbl[] = {
        { "slow", AD_LACP_SLOW, 0},
        { "fast", AD_LACP_FAST, 0},
        { NULL,   -1,           0},
 };
 
-static struct bond_opt_value bond_ad_select_tbl[] = {
+static const struct bond_opt_value bond_ad_select_tbl[] = {
        { "stable",    BOND_AD_STABLE,    BOND_VALFLAG_DEFAULT},
        { "bandwidth", BOND_AD_BANDWIDTH, 0},
        { "count",     BOND_AD_COUNT,     0},
        { NULL,        -1,                0},
 };
 
-static struct bond_opt_value bond_num_peer_notif_tbl[] = {
+static const struct bond_opt_value bond_num_peer_notif_tbl[] = {
        { "off",     0,   0},
        { "maxval",  255, BOND_VALFLAG_MAX},
        { "default", 1,   BOND_VALFLAG_DEFAULT},
        { NULL,      -1,  0}
 };
 
-static struct bond_opt_value bond_primary_reselect_tbl[] = {
+static const struct bond_opt_value bond_primary_reselect_tbl[] = {
        { "always",  BOND_PRI_RESELECT_ALWAYS,  BOND_VALFLAG_DEFAULT},
        { "better",  BOND_PRI_RESELECT_BETTER,  0},
        { "failure", BOND_PRI_RESELECT_FAILURE, 0},
        { NULL,      -1},
 };
 
-static struct bond_opt_value bond_use_carrier_tbl[] = {
+static const struct bond_opt_value bond_use_carrier_tbl[] = {
        { "off", 0,  0},
        { "on",  1,  BOND_VALFLAG_DEFAULT},
        { NULL,  -1, 0}
 };
 
-static struct bond_opt_value bond_all_slaves_active_tbl[] = {
+static const struct bond_opt_value bond_all_slaves_active_tbl[] = {
        { "off", 0,  BOND_VALFLAG_DEFAULT},
        { "on",  1,  0},
        { NULL,  -1, 0}
 };
 
-static struct bond_opt_value bond_resend_igmp_tbl[] = {
+static const struct bond_opt_value bond_resend_igmp_tbl[] = {
        { "off",     0,   0},
        { "maxval",  255, BOND_VALFLAG_MAX},
        { "default", 1,   BOND_VALFLAG_DEFAULT},
        { NULL,      -1,  0}
 };
 
-static struct bond_opt_value bond_lp_interval_tbl[] = {
+static const struct bond_opt_value bond_lp_interval_tbl[] = {
        { "minval",  1,       BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
        { "maxval",  INT_MAX, BOND_VALFLAG_MAX},
+       { NULL,      -1,      0},
 };
 
-static struct bond_option bond_opts[] = {
+static const struct bond_option bond_opts[] = {
        [BOND_OPT_MODE] = {
                .id = BOND_OPT_MODE,
                .name = "mode",
@@ -315,9 +368,9 @@ static struct bond_option bond_opts[] = {
 };
 
 /* Searches for a value in opt's values[] table */
-struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
+const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
 {
-       struct bond_option *opt;
+       const struct bond_option *opt;
        int i;
 
        opt = bond_opt_get(option);
@@ -331,7 +384,7 @@ struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
 }
 
 /* Searches for a value in opt's values[] table which matches the flagmask */
-static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
+static const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
                                                 u32 flagmask)
 {
        int i;
@@ -348,7 +401,7 @@ static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
  */
 static bool bond_opt_check_range(const struct bond_option *opt, u64 val)
 {
-       struct bond_opt_value *minval, *maxval;
+       const struct bond_opt_value *minval, *maxval;
 
        minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
        maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
@@ -368,11 +421,12 @@ static bool bond_opt_check_range(const struct bond_option *opt, u64 val)
  * or the struct_opt_value that matched. It also strips the new line from
  * @val->string if it's present.
  */
-struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
-                                     struct bond_opt_value *val)
+const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
+                                           struct bond_opt_value *val)
 {
        char *p, valstr[BOND_OPT_MAX_NAMELEN + 1] = { 0, };
-       struct bond_opt_value *tbl, *ret = NULL;
+       const struct bond_opt_value *tbl;
+       const struct bond_opt_value *ret = NULL;
        bool checkval;
        int i, rv;
 
@@ -451,7 +505,7 @@ static int bond_opt_check_deps(struct bonding *bond,
 static void bond_opt_dep_print(struct bonding *bond,
                               const struct bond_option *opt)
 {
-       struct bond_opt_value *modeval;
+       const struct bond_opt_value *modeval;
        struct bond_params *params;
 
        params = &bond->params;
@@ -464,9 +518,9 @@ static void bond_opt_dep_print(struct bonding *bond,
 
 static void bond_opt_error_interpret(struct bonding *bond,
                                     const struct bond_option *opt,
-                                    int error, struct bond_opt_value *val)
+                                    int error, const struct bond_opt_value *val)
 {
-       struct bond_opt_value *minval, *maxval;
+       const struct bond_opt_value *minval, *maxval;
        char *p;
 
        switch (error) {
@@ -521,7 +575,7 @@ static void bond_opt_error_interpret(struct bonding *bond,
 int __bond_opt_set(struct bonding *bond,
                   unsigned int option, struct bond_opt_value *val)
 {
-       struct bond_opt_value *retval = NULL;
+       const struct bond_opt_value *retval = NULL;
        const struct bond_option *opt;
        int ret = -ENOENT;
 
@@ -576,7 +630,7 @@ int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf)
  * This function checks if option is valid and if so returns a pointer
  * to its entry in the bond_opts[] option array.
  */
-struct bond_option *bond_opt_get(unsigned int option)
+const struct bond_option *bond_opt_get(unsigned int option)
 {
        if (!BOND_OPT_VALID(option))
                return NULL;
@@ -584,7 +638,7 @@ struct bond_option *bond_opt_get(unsigned int option)
        return &bond_opts[option];
 }
 
-int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval)
+int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval)
 {
        if (BOND_NO_USES_ARP(newval->value) && bond->params.arp_interval) {
                pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n",
@@ -622,8 +676,8 @@ struct net_device *bond_option_active_slave_get(struct bonding *bond)
        return __bond_option_active_slave_get(bond, bond->curr_active_slave);
 }
 
-int bond_option_active_slave_set(struct bonding *bond,
-                                struct bond_opt_value *newval)
+static int bond_option_active_slave_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval)
 {
        char ifname[IFNAMSIZ] = { 0, };
        struct net_device *slave_dev;
@@ -691,7 +745,8 @@ int bond_option_active_slave_set(struct bonding *bond,
        return ret;
 }
 
-int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_miimon_set(struct bonding *bond,
+                                 const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting MII monitoring interval to %llu\n",
                bond->dev->name, newval->value);
@@ -728,7 +783,8 @@ int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval)
        return 0;
 }
 
-int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_updelay_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval)
 {
        int value = newval->value;
 
@@ -751,8 +807,8 @@ int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval)
        return 0;
 }
 
-int bond_option_downdelay_set(struct bonding *bond,
-                             struct bond_opt_value *newval)
+static int bond_option_downdelay_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval)
 {
        int value = newval->value;
 
@@ -775,8 +831,8 @@ int bond_option_downdelay_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_use_carrier_set(struct bonding *bond,
-                               struct bond_opt_value *newval)
+static int bond_option_use_carrier_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting use_carrier to %llu\n",
                bond->dev->name, newval->value);
@@ -785,8 +841,8 @@ int bond_option_use_carrier_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_arp_interval_set(struct bonding *bond,
-                                struct bond_opt_value *newval)
+static int bond_option_arp_interval_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting ARP monitoring interval to %llu\n",
                bond->dev->name, newval->value);
@@ -867,7 +923,7 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
        return 0;
 }
 
-int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
+static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
 {
        int ret;
 
@@ -879,7 +935,7 @@ int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
        return ret;
 }
 
-int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
+static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
 {
        __be32 *targets = bond->params.arp_targets;
        struct list_head *iter;
@@ -935,8 +991,8 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond)
        write_unlock_bh(&bond->lock);
 }
 
-int bond_option_arp_ip_targets_set(struct bonding *bond,
-                                  struct bond_opt_value *newval)
+static int bond_option_arp_ip_targets_set(struct bonding *bond,
+                                         const struct bond_opt_value *newval)
 {
        int ret = -EPERM;
        __be32 target;
@@ -962,8 +1018,8 @@ int bond_option_arp_ip_targets_set(struct bonding *bond,
        return ret;
 }
 
-int bond_option_arp_validate_set(struct bonding *bond,
-                                struct bond_opt_value *newval)
+static int bond_option_arp_validate_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting arp_validate to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
@@ -979,8 +1035,8 @@ int bond_option_arp_validate_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_arp_all_targets_set(struct bonding *bond,
-                                   struct bond_opt_value *newval)
+static int bond_option_arp_all_targets_set(struct bonding *bond,
+                                          const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting arp_all_targets to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
@@ -989,7 +1045,8 @@ int bond_option_arp_all_targets_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_primary_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval)
 {
        char *p, *primary = newval->string;
        struct list_head *iter;
@@ -1041,8 +1098,8 @@ out:
        return 0;
 }
 
-int bond_option_primary_reselect_set(struct bonding *bond,
-                                    struct bond_opt_value *newval)
+static int bond_option_primary_reselect_set(struct bonding *bond,
+                                           const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting primary_reselect to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
@@ -1057,8 +1114,8 @@ int bond_option_primary_reselect_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_fail_over_mac_set(struct bonding *bond,
-                                 struct bond_opt_value *newval)
+static int bond_option_fail_over_mac_set(struct bonding *bond,
+                                        const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting fail_over_mac to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
@@ -1067,8 +1124,8 @@ int bond_option_fail_over_mac_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_xmit_hash_policy_set(struct bonding *bond,
-                                    struct bond_opt_value *newval)
+static int bond_option_xmit_hash_policy_set(struct bonding *bond,
+                                           const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting xmit hash policy to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
@@ -1077,8 +1134,8 @@ int bond_option_xmit_hash_policy_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_resend_igmp_set(struct bonding *bond,
-                               struct bond_opt_value *newval)
+static int bond_option_resend_igmp_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting resend_igmp to %llu\n",
                bond->dev->name, newval->value);
@@ -1087,16 +1144,16 @@ int bond_option_resend_igmp_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_num_peer_notif_set(struct bonding *bond,
-                                  struct bond_opt_value *newval)
+static int bond_option_num_peer_notif_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval)
 {
        bond->params.num_peer_notif = newval->value;
 
        return 0;
 }
 
-int bond_option_all_slaves_active_set(struct bonding *bond,
-                                     struct bond_opt_value *newval)
+static int bond_option_all_slaves_active_set(struct bonding *bond,
+                                            const struct bond_opt_value *newval)
 {
        struct list_head *iter;
        struct slave *slave;
@@ -1116,8 +1173,8 @@ int bond_option_all_slaves_active_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_min_links_set(struct bonding *bond,
-                             struct bond_opt_value *newval)
+static int bond_option_min_links_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting min links value to %llu\n",
                bond->dev->name, newval->value);
@@ -1126,15 +1183,16 @@ int bond_option_min_links_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_lp_interval_set(struct bonding *bond,
-                               struct bond_opt_value *newval)
+static int bond_option_lp_interval_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval)
 {
        bond->params.lp_interval = newval->value;
 
        return 0;
 }
 
-int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_pps_set(struct bonding *bond,
+                              const struct bond_opt_value *newval)
 {
        bond->params.packets_per_slave = newval->value;
        if (newval->value > 0) {
@@ -1151,8 +1209,8 @@ int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval)
        return 0;
 }
 
-int bond_option_lacp_rate_set(struct bonding *bond,
-                             struct bond_opt_value *newval)
+static int bond_option_lacp_rate_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting LACP rate to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
@@ -1162,8 +1220,8 @@ int bond_option_lacp_rate_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_ad_select_set(struct bonding *bond,
-                             struct bond_opt_value *newval)
+static int bond_option_ad_select_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting ad_select to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
@@ -1172,8 +1230,8 @@ int bond_option_ad_select_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_queue_id_set(struct bonding *bond,
-                            struct bond_opt_value *newval)
+static int bond_option_queue_id_set(struct bonding *bond,
+                                   const struct bond_opt_value *newval)
 {
        struct slave *slave, *update_slave;
        struct net_device *sdev;
@@ -1233,7 +1291,8 @@ err_no_cmd:
 
 }
 
-int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_slaves_set(struct bonding *bond,
+                                 const struct bond_opt_value *newval)
 {
        char command[IFNAMSIZ + 1] = { 0, };
        struct net_device *dev;
index 433d37f6940b997649147ba4d8c0f415bdba47c9..12be9e1bfb0c0d048229a1698c2b384847fbd794 100644 (file)
@@ -81,8 +81,8 @@ struct bonding;
 
 struct bond_option {
        int id;
-       char *name;
-       char *desc;
+       const char *name;
+       const char *desc;
        u32 flags;
 
        /* unsuppmodes is used to denote modes in which the option isn't
@@ -92,18 +92,19 @@ struct bond_option {
        /* supported values which this option can have, can be a subset of
         * BOND_OPTVAL_RANGE's value range
         */
-       struct bond_opt_value *values;
+       const struct bond_opt_value *values;
 
-       int (*set)(struct bonding *bond, struct bond_opt_value *val);
+       int (*set)(struct bonding *bond, const struct bond_opt_value *val);
 };
 
 int __bond_opt_set(struct bonding *bond, unsigned int option,
                   struct bond_opt_value *val);
 int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf);
-struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
-                                     struct bond_opt_value *val);
-struct bond_option *bond_opt_get(unsigned int option);
-struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
+
+const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
+                                           struct bond_opt_value *val);
+const struct bond_option *bond_opt_get(unsigned int option);
+const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
 
 /* This helper is used to initialize a bond_opt_value structure for parameter
  * passing. There should be either a valid string or value, but not both.
@@ -122,49 +123,6 @@ static inline void __bond_opt_init(struct bond_opt_value *optval,
 #define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value)
 #define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX)
 
-int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval);
-int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval);
-int bond_option_xmit_hash_policy_set(struct bonding *bond,
-                                    struct bond_opt_value *newval);
-int bond_option_arp_validate_set(struct bonding *bond,
-                                struct bond_opt_value *newval);
-int bond_option_arp_all_targets_set(struct bonding *bond,
-                                   struct bond_opt_value *newval);
-int bond_option_fail_over_mac_set(struct bonding *bond,
-                                 struct bond_opt_value *newval);
-int bond_option_arp_interval_set(struct bonding *bond,
-                                struct bond_opt_value *newval);
-int bond_option_arp_ip_targets_set(struct bonding *bond,
-                                  struct bond_opt_value *newval);
 void bond_option_arp_ip_targets_clear(struct bonding *bond);
-int bond_option_downdelay_set(struct bonding *bond,
-                             struct bond_opt_value *newval);
-int bond_option_updelay_set(struct bonding *bond,
-                           struct bond_opt_value *newval);
-int bond_option_lacp_rate_set(struct bonding *bond,
-                             struct bond_opt_value *newval);
-int bond_option_min_links_set(struct bonding *bond,
-                             struct bond_opt_value *newval);
-int bond_option_ad_select_set(struct bonding *bond,
-                             struct bond_opt_value *newval);
-int bond_option_num_peer_notif_set(struct bonding *bond,
-                                  struct bond_opt_value *newval);
-int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval);
-int bond_option_primary_set(struct bonding *bond,
-                           struct bond_opt_value *newval);
-int bond_option_primary_reselect_set(struct bonding *bond,
-                                    struct bond_opt_value *newval);
-int bond_option_use_carrier_set(struct bonding *bond,
-                               struct bond_opt_value *newval);
-int bond_option_active_slave_set(struct bonding *bond,
-                                struct bond_opt_value *newval);
-int bond_option_queue_id_set(struct bonding *bond,
-                            struct bond_opt_value *newval);
-int bond_option_all_slaves_active_set(struct bonding *bond,
-                                     struct bond_opt_value *newval);
-int bond_option_resend_igmp_set(struct bonding *bond,
-                               struct bond_opt_value *newval);
-int bond_option_lp_interval_set(struct bonding *bond,
-                               struct bond_opt_value *newval);
-int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval);
+
 #endif /* _BOND_OPTIONS_H */
index 588cf39d832ce7153192d337b66fe936c0f3f840..013fdd0f45e94340917ee2aeecc8529d386862e2 100644 (file)
@@ -65,7 +65,7 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v)
 static void bond_info_show_master(struct seq_file *seq)
 {
        struct bonding *bond = seq->private;
-       struct bond_opt_value *optval;
+       const struct bond_opt_value *optval;
        struct slave *curr;
        int i;
 
index 225ee696db059bca47f1372e2f610d232bd23ad2..0e8b268da0a08f58c4443c6c36aa62bb9ef0f071 100644 (file)
@@ -220,7 +220,7 @@ static ssize_t bonding_show_mode(struct device *d,
                                 struct device_attribute *attr, char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode);
 
@@ -251,7 +251,7 @@ static ssize_t bonding_show_xmit_hash(struct device *d,
                                      char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_XMIT_HASH, bond->params.xmit_policy);
 
@@ -282,7 +282,7 @@ static ssize_t bonding_show_arp_validate(struct device *d,
                                         char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_ARP_VALIDATE,
                               bond->params.arp_validate);
@@ -314,7 +314,7 @@ static ssize_t bonding_show_arp_all_targets(struct device *d,
                                         char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_ARP_ALL_TARGETS,
                               bond->params.arp_all_targets);
@@ -348,7 +348,7 @@ static ssize_t bonding_show_fail_over_mac(struct device *d,
                                          char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC,
                               bond->params.fail_over_mac);
@@ -505,7 +505,7 @@ static ssize_t bonding_show_lacp(struct device *d,
                                 char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_LACP_RATE, bond->params.lacp_fast);
 
@@ -558,7 +558,7 @@ static ssize_t bonding_show_ad_select(struct device *d,
                                      char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_AD_SELECT, bond->params.ad_select);
 
@@ -686,7 +686,7 @@ static ssize_t bonding_show_primary_reselect(struct device *d,
                                             char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT,
                               bond->params.primary_reselect);
index 430362891d0d16dd072f558b6bb368cf140e3256..0896f1db24db6a334c91129e5716fb5c32d1c855 100644 (file)
@@ -196,7 +196,8 @@ struct slave {
        s8     new_link;
        u8     backup:1,   /* indicates backup slave. Value corresponds with
                              BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
-              inactive:1; /* indicates inactive slave */
+              inactive:1, /* indicates inactive slave */
+              should_notify:1; /* indicateds whether the state changed */
        u8     duplex;
        u32    original_mtu;
        u32    link_failure_count;
@@ -292,7 +293,7 @@ static inline void bond_set_active_slave(struct slave *slave)
 {
        if (slave->backup) {
                slave->backup = 0;
-               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
+               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
        }
 }
 
@@ -300,7 +301,25 @@ static inline void bond_set_backup_slave(struct slave *slave)
 {
        if (!slave->backup) {
                slave->backup = 1;
-               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
+               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
+       }
+}
+
+static inline void bond_set_slave_state(struct slave *slave,
+                                       int slave_state, bool notify)
+{
+       if (slave->backup == slave_state)
+               return;
+
+       slave->backup = slave_state;
+       if (notify) {
+               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
+               slave->should_notify = 0;
+       } else {
+               if (slave->should_notify)
+                       slave->should_notify = 0;
+               else
+                       slave->should_notify = 1;
        }
 }
 
@@ -317,6 +336,19 @@ static inline void bond_slave_state_change(struct bonding *bond)
        }
 }
 
+static inline void bond_slave_state_notify(struct bonding *bond)
+{
+       struct list_head *iter;
+       struct slave *tmp;
+
+       bond_for_each_slave(bond, tmp, iter) {
+               if (tmp->should_notify) {
+                       rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_ATOMIC);
+                       tmp->should_notify = 0;
+               }
+       }
+}
+
 static inline int bond_slave_state(struct slave *slave)
 {
        return slave->backup;
@@ -349,6 +381,9 @@ static inline bool bond_is_active_slave(struct slave *slave)
 #define BOND_ARP_FILTER_BACKUP         (BOND_ARP_VALIDATE_BACKUP | \
                                         BOND_ARP_FILTER)
 
+#define BOND_SLAVE_NOTIFY_NOW          true
+#define BOND_SLAVE_NOTIFY_LATER                false
+
 static inline int slave_do_arp_validate(struct bonding *bond,
                                        struct slave *slave)
 {
@@ -402,17 +437,19 @@ static inline void bond_netpoll_send_skb(const struct slave *slave,
 }
 #endif
 
-static inline void bond_set_slave_inactive_flags(struct slave *slave)
+static inline void bond_set_slave_inactive_flags(struct slave *slave,
+                                                bool notify)
 {
        if (!bond_is_lb(slave->bond))
-               bond_set_backup_slave(slave);
+               bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
        if (!slave->bond->params.all_slaves_active)
                slave->inactive = 1;
 }
 
-static inline void bond_set_slave_active_flags(struct slave *slave)
+static inline void bond_set_slave_active_flags(struct slave *slave,
+                                              bool notify)
 {
-       bond_set_active_slave(slave);
+       bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify);
        slave->inactive = 0;
 }
 
@@ -458,8 +495,6 @@ void bond_sysfs_slave_del(struct slave *slave);
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
 int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
 int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count);
-int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl);
-int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl);
 void bond_select_active_slave(struct bonding *bond);
 void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
 void bond_create_debugfs(void);
@@ -472,8 +507,6 @@ void bond_setup(struct net_device *bond_dev);
 unsigned int bond_get_num_tx_queues(void);
 int bond_netlink_init(void);
 void bond_netlink_fini(void);
-int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
-int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
 struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
 struct net_device *bond_option_active_slave_get(struct bonding *bond);
 const char *bond_slave_link_status(s8 link);
index c0563f18372177856783b938408fda260c5be3b1..c7a260478749ad163ec133df88e7a0086b220a73 100644 (file)
@@ -99,10 +99,10 @@ static int can_update_spt(const struct can_bittiming_const *btc,
        return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
 }
 
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
+                             const struct can_bittiming_const *btc)
 {
        struct can_priv *priv = netdev_priv(dev);
-       const struct can_bittiming_const *btc = priv->bittiming_const;
        long rate, best_rate = 0;
        long best_error = 1000000000, error = 0;
        int best_tseg = 0, best_brp = 0, brp = 0;
@@ -110,9 +110,6 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
        int spt_error = 1000, spt = 0, sampl_pt;
        u64 v64;
 
-       if (!priv->bittiming_const)
-               return -ENOTSUPP;
-
        /* Use CIA recommended sample points */
        if (bt->sample_point) {
                sampl_pt = bt->sample_point;
@@ -204,7 +201,8 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
        return 0;
 }
 #else /* !CONFIG_CAN_CALC_BITTIMING */
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
+                             const struct can_bittiming_const *btc)
 {
        netdev_err(dev, "bit-timing calculation not available\n");
        return -EINVAL;
@@ -217,16 +215,13 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
  * prescaler value brp. You can find more information in the header
  * file linux/can/netlink.h.
  */
-static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
+                              const struct can_bittiming_const *btc)
 {
        struct can_priv *priv = netdev_priv(dev);
-       const struct can_bittiming_const *btc = priv->bittiming_const;
        int tseg1, alltseg;
        u64 brp64;
 
-       if (!priv->bittiming_const)
-               return -ENOTSUPP;
-
        tseg1 = bt->prop_seg + bt->phase_seg1;
        if (!bt->sjw)
                bt->sjw = 1;
@@ -254,26 +249,29 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt)
        return 0;
 }
 
-static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
+                            const struct can_bittiming_const *btc)
 {
-       struct can_priv *priv = netdev_priv(dev);
        int err;
 
        /* Check if the CAN device has bit-timing parameters */
-       if (priv->bittiming_const) {
+       if (!btc)
+               return -ENOTSUPP;
 
-               /* Non-expert mode? Check if the bitrate has been pre-defined */
-               if (!bt->tq)
-                       /* Determine bit-timing parameters */
-                       err = can_calc_bittiming(dev, bt);
-               else
-                       /* Check bit-timing params and calculate proper brp */
-                       err = can_fixup_bittiming(dev, bt);
-               if (err)
-                       return err;
-       }
+       /*
+        * Depending on the given can_bittiming parameter structure the CAN
+        * timing parameters are calculated based on the provided bitrate OR
+        * alternatively the CAN timing parameters (tq, prop_seg, etc.) are
+        * provided directly which are then checked and fixed up.
+        */
+       if (!bt->tq && bt->bitrate)
+               err = can_calc_bittiming(dev, bt, btc);
+       else if (bt->tq && !bt->bitrate)
+               err = can_fixup_bittiming(dev, bt, btc);
+       else
+               err = -EINVAL;
 
-       return 0;
+       return err;
 }
 
 /*
@@ -317,7 +315,9 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
        BUG_ON(idx >= priv->echo_skb_max);
 
        /* check flag whether this packet has to be looped back */
-       if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) {
+       if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
+           (skb->protocol != htons(ETH_P_CAN) &&
+            skb->protocol != htons(ETH_P_CANFD))) {
                kfree_skb(skb);
                return;
        }
@@ -329,7 +329,6 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
                        return;
 
                /* make settings for echo to reduce code in irq context */
-               skb->protocol = htons(ETH_P_CAN);
                skb->pkt_type = PACKET_BROADCAST;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
                skb->dev = dev;
@@ -595,6 +594,39 @@ void free_candev(struct net_device *dev)
 }
 EXPORT_SYMBOL_GPL(free_candev);
 
+/*
+ * changing MTU and control mode for CAN/CANFD devices
+ */
+int can_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       /* Do not allow changing the MTU while running */
+       if (dev->flags & IFF_UP)
+               return -EBUSY;
+
+       /* allow change of MTU according to the CANFD ability of the device */
+       switch (new_mtu) {
+       case CAN_MTU:
+               priv->ctrlmode &= ~CAN_CTRLMODE_FD;
+               break;
+
+       case CANFD_MTU:
+               if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD))
+                       return -EINVAL;
+
+               priv->ctrlmode |= CAN_CTRLMODE_FD;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(can_change_mtu);
+
 /*
  * Common open function when the device gets opened.
  *
@@ -605,11 +637,19 @@ int open_candev(struct net_device *dev)
 {
        struct can_priv *priv = netdev_priv(dev);
 
-       if (!priv->bittiming.tq && !priv->bittiming.bitrate) {
+       if (!priv->bittiming.bitrate) {
                netdev_err(dev, "bit-timing not yet defined\n");
                return -EINVAL;
        }
 
+       /* For CAN FD the data bitrate has to be >= the arbitration bitrate */
+       if ((priv->ctrlmode & CAN_CTRLMODE_FD) &&
+           (!priv->data_bittiming.bitrate ||
+            (priv->data_bittiming.bitrate < priv->bittiming.bitrate))) {
+               netdev_err(dev, "incorrect/missing data bit-timing\n");
+               return -EINVAL;
+       }
+
        /* Switch carrier on if device was stopped while in bus-off state */
        if (!netif_carrier_ok(dev))
                netif_carrier_on(dev);
@@ -648,6 +688,10 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
                                = { .len = sizeof(struct can_bittiming_const) },
        [IFLA_CAN_CLOCK]        = { .len = sizeof(struct can_clock) },
        [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
+       [IFLA_CAN_DATA_BITTIMING]
+                               = { .len = sizeof(struct can_bittiming) },
+       [IFLA_CAN_DATA_BITTIMING_CONST]
+                               = { .len = sizeof(struct can_bittiming_const) },
 };
 
 static int can_changelink(struct net_device *dev,
@@ -666,9 +710,7 @@ static int can_changelink(struct net_device *dev,
                if (dev->flags & IFF_UP)
                        return -EBUSY;
                memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
-               if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq))
-                       return -EINVAL;
-               err = can_get_bittiming(dev, &bt);
+               err = can_get_bittiming(dev, &bt, priv->bittiming_const);
                if (err)
                        return err;
                memcpy(&priv->bittiming, &bt, sizeof(bt));
@@ -692,6 +734,12 @@ static int can_changelink(struct net_device *dev,
                        return -EOPNOTSUPP;
                priv->ctrlmode &= ~cm->mask;
                priv->ctrlmode |= cm->flags;
+
+               /* CAN_CTRLMODE_FD can only be set when driver supports FD */
+               if (priv->ctrlmode & CAN_CTRLMODE_FD)
+                       dev->mtu = CANFD_MTU;
+               else
+                       dev->mtu = CAN_MTU;
        }
 
        if (data[IFLA_CAN_RESTART_MS]) {
@@ -710,6 +758,27 @@ static int can_changelink(struct net_device *dev,
                        return err;
        }
 
+       if (data[IFLA_CAN_DATA_BITTIMING]) {
+               struct can_bittiming dbt;
+
+               /* Do not allow changing bittiming while running */
+               if (dev->flags & IFF_UP)
+                       return -EBUSY;
+               memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
+                      sizeof(dbt));
+               err = can_get_bittiming(dev, &dbt, priv->data_bittiming_const);
+               if (err)
+                       return err;
+               memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
+
+               if (priv->do_set_data_bittiming) {
+                       /* Finally, set the bit-timing registers */
+                       err = priv->do_set_data_bittiming(dev);
+                       if (err)
+                               return err;
+               }
+       }
+
        return 0;
 }
 
@@ -718,7 +787,8 @@ static size_t can_get_size(const struct net_device *dev)
        struct can_priv *priv = netdev_priv(dev);
        size_t size = 0;
 
-       size += nla_total_size(sizeof(struct can_bittiming));   /* IFLA_CAN_BITTIMING */
+       if (priv->bittiming.bitrate)                            /* IFLA_CAN_BITTIMING */
+               size += nla_total_size(sizeof(struct can_bittiming));
        if (priv->bittiming_const)                              /* IFLA_CAN_BITTIMING_CONST */
                size += nla_total_size(sizeof(struct can_bittiming_const));
        size += nla_total_size(sizeof(struct can_clock));       /* IFLA_CAN_CLOCK */
@@ -727,6 +797,10 @@ static size_t can_get_size(const struct net_device *dev)
        size += nla_total_size(sizeof(u32));                    /* IFLA_CAN_RESTART_MS */
        if (priv->do_get_berr_counter)                          /* IFLA_CAN_BERR_COUNTER */
                size += nla_total_size(sizeof(struct can_berr_counter));
+       if (priv->data_bittiming.bitrate)                       /* IFLA_CAN_DATA_BITTIMING */
+               size += nla_total_size(sizeof(struct can_bittiming));
+       if (priv->data_bittiming_const)                         /* IFLA_CAN_DATA_BITTIMING_CONST */
+               size += nla_total_size(sizeof(struct can_bittiming_const));
 
        return size;
 }
@@ -740,19 +814,34 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
 
        if (priv->do_get_state)
                priv->do_get_state(dev, &state);
-       if (nla_put(skb, IFLA_CAN_BITTIMING,
-                   sizeof(priv->bittiming), &priv->bittiming) ||
+
+       if ((priv->bittiming.bitrate &&
+            nla_put(skb, IFLA_CAN_BITTIMING,
+                    sizeof(priv->bittiming), &priv->bittiming)) ||
+
            (priv->bittiming_const &&
             nla_put(skb, IFLA_CAN_BITTIMING_CONST,
                     sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
+
            nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) ||
            nla_put_u32(skb, IFLA_CAN_STATE, state) ||
            nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
            nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
+
            (priv->do_get_berr_counter &&
             !priv->do_get_berr_counter(dev, &bec) &&
-            nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)))
+            nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
+
+           (priv->data_bittiming.bitrate &&
+            nla_put(skb, IFLA_CAN_DATA_BITTIMING,
+                    sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
+
+           (priv->data_bittiming_const &&
+            nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
+                    sizeof(*priv->data_bittiming_const),
+                    priv->data_bittiming_const)))
                return -EMSGSIZE;
+
        return 0;
 }
 
index 320bef2dba427f266511330bc11b1a4097368520..c94d698b73c2d85bfcc23823d4d453e0d5a491b6 100644 (file)
 
 #define FLEXCAN_MB_CODE_MASK           (0xf0ffffff)
 
+#define FLEXCAN_TIMEOUT_US             (50)
+
 /*
  * FLEXCAN hardware feature flags
  *
@@ -262,6 +264,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
 }
 #endif
 
+static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
+{
+       if (!priv->reg_xceiver)
+               return 0;
+
+       return regulator_enable(priv->reg_xceiver);
+}
+
+static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv)
+{
+       if (!priv->reg_xceiver)
+               return 0;
+
+       return regulator_disable(priv->reg_xceiver);
+}
+
 static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
                                              u32 reg_esr)
 {
@@ -269,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
                (reg_esr & FLEXCAN_ESR_ERR_BUS);
 }
 
-static inline void flexcan_chip_enable(struct flexcan_priv *priv)
+static int flexcan_chip_enable(struct flexcan_priv *priv)
 {
        struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
        u32 reg;
 
        reg = flexcan_read(&regs->mcr);
        reg &= ~FLEXCAN_MCR_MDIS;
        flexcan_write(reg, &regs->mcr);
 
-       udelay(10);
+       while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+               usleep_range(10, 20);
+
+       if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
+               return -ETIMEDOUT;
+
+       return 0;
 }
 
-static inline void flexcan_chip_disable(struct flexcan_priv *priv)
+static int flexcan_chip_disable(struct flexcan_priv *priv)
 {
        struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
        u32 reg;
 
        reg = flexcan_read(&regs->mcr);
        reg |= FLEXCAN_MCR_MDIS;
        flexcan_write(reg, &regs->mcr);
+
+       while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+               usleep_range(10, 20);
+
+       if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int flexcan_chip_freeze(struct flexcan_priv *priv)
+{
+       struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
+       u32 reg;
+
+       reg = flexcan_read(&regs->mcr);
+       reg |= FLEXCAN_MCR_HALT;
+       flexcan_write(reg, &regs->mcr);
+
+       while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+               usleep_range(100, 200);
+
+       if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
+{
+       struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+       u32 reg;
+
+       reg = flexcan_read(&regs->mcr);
+       reg &= ~FLEXCAN_MCR_HALT;
+       flexcan_write(reg, &regs->mcr);
+
+       while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+               usleep_range(10, 20);
+
+       if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int flexcan_chip_softreset(struct flexcan_priv *priv)
+{
+       struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+
+       flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
+       while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST))
+               usleep_range(10, 20);
+
+       if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST)
+               return -ETIMEDOUT;
+
+       return 0;
 }
 
 static int flexcan_get_berr_counter(const struct net_device *dev,
@@ -709,19 +796,14 @@ static int flexcan_chip_start(struct net_device *dev)
        u32 reg_mcr, reg_ctrl;
 
        /* enable module */
-       flexcan_chip_enable(priv);
+       err = flexcan_chip_enable(priv);
+       if (err)
+               return err;
 
        /* soft reset */
-       flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
-       udelay(10);
-
-       reg_mcr = flexcan_read(&regs->mcr);
-       if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
-               netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n",
-                          reg_mcr);
-               err = -ENODEV;
-               goto out;
-       }
+       err = flexcan_chip_softreset(priv);
+       if (err)
+               goto out_chip_disable;
 
        flexcan_set_bittiming(dev);
 
@@ -788,16 +870,14 @@ static int flexcan_chip_start(struct net_device *dev)
        if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
                flexcan_write(0x0, &regs->rxfgmask);
 
-       if (priv->reg_xceiver)  {
-               err = regulator_enable(priv->reg_xceiver);
-               if (err)
-                       goto out;
-       }
+       err = flexcan_transceiver_enable(priv);
+       if (err)
+               goto out_chip_disable;
 
        /* synchronize with the can bus */
-       reg_mcr = flexcan_read(&regs->mcr);
-       reg_mcr &= ~FLEXCAN_MCR_HALT;
-       flexcan_write(reg_mcr, &regs->mcr);
+       err = flexcan_chip_unfreeze(priv);
+       if (err)
+               goto out_transceiver_disable;
 
        priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
@@ -810,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev)
 
        return 0;
 
- out:
+ out_transceiver_disable:
+       flexcan_transceiver_disable(priv);
+ out_chip_disable:
        flexcan_chip_disable(priv);
        return err;
 }
@@ -825,18 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev)
 {
        struct flexcan_priv *priv = netdev_priv(dev);
        struct flexcan_regs __iomem *regs = priv->base;
-       u32 reg;
+
+       /* freeze + disable module */
+       flexcan_chip_freeze(priv);
+       flexcan_chip_disable(priv);
 
        /* Disable all interrupts */
        flexcan_write(0, &regs->imask1);
+       flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
+                     &regs->ctrl);
 
-       /* Disable + halt module */
-       reg = flexcan_read(&regs->mcr);
-       reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
-       flexcan_write(reg, &regs->mcr);
-
-       if (priv->reg_xceiver)
-               regulator_disable(priv->reg_xceiver);
+       flexcan_transceiver_disable(priv);
        priv->can.state = CAN_STATE_STOPPED;
 
        return;
@@ -866,7 +947,7 @@ static int flexcan_open(struct net_device *dev)
        /* start chip and queuing */
        err = flexcan_chip_start(dev);
        if (err)
-               goto out_close;
+               goto out_free_irq;
 
        can_led_event(dev, CAN_LED_EVENT_OPEN);
 
@@ -875,6 +956,8 @@ static int flexcan_open(struct net_device *dev)
 
        return 0;
 
+ out_free_irq:
+       free_irq(dev->irq, dev);
  out_close:
        close_candev(dev);
  out_disable_per:
@@ -945,12 +1028,16 @@ static int register_flexcandev(struct net_device *dev)
                goto out_disable_ipg;
 
        /* select "bus clock", chip must be disabled */
-       flexcan_chip_disable(priv);
+       err = flexcan_chip_disable(priv);
+       if (err)
+               goto out_disable_per;
        reg = flexcan_read(&regs->ctrl);
        reg |= FLEXCAN_CTRL_CLK_SRC;
        flexcan_write(reg, &regs->ctrl);
 
-       flexcan_chip_enable(priv);
+       err = flexcan_chip_enable(priv);
+       if (err)
+               goto out_chip_disable;
 
        /* set freeze, halt and activate FIFO, restrict register access */
        reg = flexcan_read(&regs->mcr);
@@ -967,14 +1054,15 @@ static int register_flexcandev(struct net_device *dev)
        if (!(reg & FLEXCAN_MCR_FEN)) {
                netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
                err = -ENODEV;
-               goto out_disable_per;
+               goto out_chip_disable;
        }
 
        err = register_candev(dev);
 
- out_disable_per:
        /* disable core and turn off clocks */
+ out_chip_disable:
        flexcan_chip_disable(priv);
+ out_disable_per:
        clk_disable_unprepare(priv->clk_per);
  out_disable_ipg:
        clk_disable_unprepare(priv->clk_ipg);
@@ -1044,9 +1132,9 @@ static int flexcan_probe(struct platform_device *pdev)
        of_id = of_match_device(flexcan_of_match, &pdev->dev);
        if (of_id) {
                devtype_data = of_id->data;
-       } else if (pdev->id_entry->driver_data) {
+       } else if (platform_get_device_id(pdev)->driver_data) {
                devtype_data = (struct flexcan_devtype_data *)
-                       pdev->id_entry->driver_data;
+                       platform_get_device_id(pdev)->driver_data;
        } else {
                return -ENODEV;
        }
@@ -1104,21 +1192,24 @@ static int flexcan_probe(struct platform_device *pdev)
 static int flexcan_remove(struct platform_device *pdev)
 {
        struct net_device *dev = platform_get_drvdata(pdev);
+       struct flexcan_priv *priv = netdev_priv(dev);
 
        unregister_flexcandev(dev);
-
+       netif_napi_del(&priv->napi);
        free_candev(dev);
 
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int flexcan_suspend(struct device *device)
+static int __maybe_unused flexcan_suspend(struct device *device)
 {
        struct net_device *dev = dev_get_drvdata(device);
        struct flexcan_priv *priv = netdev_priv(dev);
+       int err;
 
-       flexcan_chip_disable(priv);
+       err = flexcan_chip_disable(priv);
+       if (err)
+               return err;
 
        if (netif_running(dev)) {
                netif_stop_queue(dev);
@@ -1129,7 +1220,7 @@ static int flexcan_suspend(struct device *device)
        return 0;
 }
 
-static int flexcan_resume(struct device *device)
+static int __maybe_unused flexcan_resume(struct device *device)
 {
        struct net_device *dev = dev_get_drvdata(device);
        struct flexcan_priv *priv = netdev_priv(dev);
@@ -1139,11 +1230,8 @@ static int flexcan_resume(struct device *device)
                netif_device_attach(dev);
                netif_start_queue(dev);
        }
-       flexcan_chip_enable(priv);
-
-       return 0;
+       return flexcan_chip_enable(priv);
 }
-#endif /* CONFIG_PM_SLEEP */
 
 static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
 
index 71594e5676fdc31fc422a542cb1786013a0f4ea4..b47df5e482fa596aea172d3667fcaceb2064fbab 100644 (file)
@@ -198,9 +198,6 @@ struct ican3_dev {
        struct net_device *ndev;
        struct napi_struct napi;
 
-       /* Device for printing */
-       struct device *dev;
-
        /* module number */
        unsigned int num;
 
@@ -295,7 +292,7 @@ static int ican3_old_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
        xord = locl ^ peer;
 
        if ((xord & MSYNC_RB_MASK) == 0x00) {
-               dev_dbg(mod->dev, "no mbox for reading\n");
+               netdev_dbg(mod->ndev, "no mbox for reading\n");
                return -ENOMEM;
        }
 
@@ -340,7 +337,7 @@ static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
        xord = locl ^ peer;
 
        if ((xord & MSYNC_WB_MASK) == MSYNC_WB_MASK) {
-               dev_err(mod->dev, "no mbox for writing\n");
+               netdev_err(mod->ndev, "no mbox for writing\n");
                return -ENOMEM;
        }
 
@@ -542,7 +539,7 @@ static int ican3_new_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
        memcpy_fromio(&desc, desc_addr, sizeof(desc));
 
        if (!(desc.control & DESC_VALID)) {
-               dev_dbg(mod->dev, "%s: no free buffers\n", __func__);
+               netdev_dbg(mod->ndev, "%s: no free buffers\n", __func__);
                return -ENOMEM;
        }
 
@@ -573,7 +570,7 @@ static int ican3_new_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
        memcpy_fromio(&desc, desc_addr, sizeof(desc));
 
        if (!(desc.control & DESC_VALID)) {
-               dev_dbg(mod->dev, "%s: no buffers to recv\n", __func__);
+               netdev_dbg(mod->ndev, "%s: no buffers to recv\n", __func__);
                return -ENOMEM;
        }
 
@@ -883,7 +880,7 @@ static void can_frame_to_ican3(struct ican3_dev *mod,
  */
 static void ican3_handle_idvers(struct ican3_dev *mod, struct ican3_msg *msg)
 {
-       dev_dbg(mod->dev, "IDVERS response: %s\n", msg->data);
+       netdev_dbg(mod->ndev, "IDVERS response: %s\n", msg->data);
 }
 
 static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
@@ -899,7 +896,7 @@ static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
         * error frame for userspace
         */
        if (msg->spec == MSG_MSGLOST) {
-               dev_err(mod->dev, "lost %d control messages\n", msg->data[0]);
+               netdev_err(mod->ndev, "lost %d control messages\n", msg->data[0]);
                return;
        }
 
@@ -939,13 +936,13 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
 
        /* we can only handle the SJA1000 part */
        if (msg->data[1] != CEVTIND_CHIP_SJA1000) {
-               dev_err(mod->dev, "unable to handle errors on non-SJA1000\n");
+               netdev_err(mod->ndev, "unable to handle errors on non-SJA1000\n");
                return -ENODEV;
        }
 
        /* check the message length for sanity */
        if (le16_to_cpu(msg->len) < 6) {
-               dev_err(mod->dev, "error message too short\n");
+               netdev_err(mod->ndev, "error message too short\n");
                return -EINVAL;
        }
 
@@ -967,7 +964,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
         */
        if (isrc == CEVTIND_BEI) {
                int ret;
-               dev_dbg(mod->dev, "bus error interrupt\n");
+               netdev_dbg(mod->ndev, "bus error interrupt\n");
 
                /* TX error */
                if (!(ecc & ECC_DIR)) {
@@ -983,7 +980,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
                 */
                ret = ican3_set_buserror(mod, 1);
                if (ret) {
-                       dev_err(mod->dev, "unable to re-enable bus-error\n");
+                       netdev_err(mod->ndev, "unable to re-enable bus-error\n");
                        return ret;
                }
 
@@ -998,7 +995,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
 
        /* data overrun interrupt */
        if (isrc == CEVTIND_DOI || isrc == CEVTIND_LOST) {
-               dev_dbg(mod->dev, "data overrun interrupt\n");
+               netdev_dbg(mod->ndev, "data overrun interrupt\n");
                cf->can_id |= CAN_ERR_CRTL;
                cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
                stats->rx_over_errors++;
@@ -1007,7 +1004,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
 
        /* error warning + passive interrupt */
        if (isrc == CEVTIND_EI) {
-               dev_dbg(mod->dev, "error warning + passive interrupt\n");
+               netdev_dbg(mod->ndev, "error warning + passive interrupt\n");
                if (status & SR_BS) {
                        state = CAN_STATE_BUS_OFF;
                        cf->can_id |= CAN_ERR_BUSOFF;
@@ -1088,7 +1085,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
                complete(&mod->termination_comp);
                break;
        default:
-               dev_err(mod->dev, "received an unknown inquiry response\n");
+               netdev_err(mod->ndev, "received an unknown inquiry response\n");
                break;
        }
 }
@@ -1096,7 +1093,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
 static void ican3_handle_unknown_message(struct ican3_dev *mod,
                                        struct ican3_msg *msg)
 {
-       dev_warn(mod->dev, "received unknown message: spec 0x%.2x length %d\n",
+       netdev_warn(mod->ndev, "received unknown message: spec 0x%.2x length %d\n",
                           msg->spec, le16_to_cpu(msg->len));
 }
 
@@ -1105,7 +1102,7 @@ static void ican3_handle_unknown_message(struct ican3_dev *mod,
  */
 static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
 {
-       dev_dbg(mod->dev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
+       netdev_dbg(mod->ndev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
                           mod->num, msg->spec, le16_to_cpu(msg->len));
 
        switch (msg->spec) {
@@ -1406,7 +1403,7 @@ static int ican3_reset_module(struct ican3_dev *mod)
                msleep(10);
        } while (time_before(jiffies, start + HZ / 4));
 
-       dev_err(mod->dev, "failed to reset CAN module\n");
+       netdev_err(mod->ndev, "failed to reset CAN module\n");
        return -ETIMEDOUT;
 }
 
@@ -1425,7 +1422,7 @@ static int ican3_startup_module(struct ican3_dev *mod)
 
        ret = ican3_reset_module(mod);
        if (ret) {
-               dev_err(mod->dev, "unable to reset module\n");
+               netdev_err(mod->ndev, "unable to reset module\n");
                return ret;
        }
 
@@ -1434,41 +1431,41 @@ static int ican3_startup_module(struct ican3_dev *mod)
 
        ret = ican3_msg_connect(mod);
        if (ret) {
-               dev_err(mod->dev, "unable to connect to module\n");
+               netdev_err(mod->ndev, "unable to connect to module\n");
                return ret;
        }
 
        ican3_init_new_host_interface(mod);
        ret = ican3_msg_newhostif(mod);
        if (ret) {
-               dev_err(mod->dev, "unable to switch to new-style interface\n");
+               netdev_err(mod->ndev, "unable to switch to new-style interface\n");
                return ret;
        }
 
        /* default to "termination on" */
        ret = ican3_set_termination(mod, true);
        if (ret) {
-               dev_err(mod->dev, "unable to enable termination\n");
+               netdev_err(mod->ndev, "unable to enable termination\n");
                return ret;
        }
 
        /* default to "bus errors enabled" */
        ret = ican3_set_buserror(mod, 1);
        if (ret) {
-               dev_err(mod->dev, "unable to set bus-error\n");
+               netdev_err(mod->ndev, "unable to set bus-error\n");
                return ret;
        }
 
        ican3_init_fast_host_interface(mod);
        ret = ican3_msg_fasthostif(mod);
        if (ret) {
-               dev_err(mod->dev, "unable to switch to fast host interface\n");
+               netdev_err(mod->ndev, "unable to switch to fast host interface\n");
                return ret;
        }
 
        ret = ican3_set_id_filter(mod, true);
        if (ret) {
-               dev_err(mod->dev, "unable to set acceptance filter\n");
+               netdev_err(mod->ndev, "unable to set acceptance filter\n");
                return ret;
        }
 
@@ -1487,14 +1484,14 @@ static int ican3_open(struct net_device *ndev)
        /* open the CAN layer */
        ret = open_candev(ndev);
        if (ret) {
-               dev_err(mod->dev, "unable to start CAN layer\n");
+               netdev_err(mod->ndev, "unable to start CAN layer\n");
                return ret;
        }
 
        /* bring the bus online */
        ret = ican3_set_bus_state(mod, true);
        if (ret) {
-               dev_err(mod->dev, "unable to set bus-on\n");
+               netdev_err(mod->ndev, "unable to set bus-on\n");
                close_candev(ndev);
                return ret;
        }
@@ -1518,7 +1515,7 @@ static int ican3_stop(struct net_device *ndev)
        /* bring the bus offline, stop receiving packets */
        ret = ican3_set_bus_state(mod, false);
        if (ret) {
-               dev_err(mod->dev, "unable to set bus-off\n");
+               netdev_err(mod->ndev, "unable to set bus-off\n");
                return ret;
        }
 
@@ -1545,7 +1542,7 @@ static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        /* check that we can actually transmit */
        if (!ican3_txok(mod)) {
-               dev_err(mod->dev, "BUG: no free descriptors\n");
+               netdev_err(mod->ndev, "BUG: no free descriptors\n");
                spin_unlock_irqrestore(&mod->lock, flags);
                return NETDEV_TX_BUSY;
        }
@@ -1657,7 +1654,7 @@ static int ican3_set_mode(struct net_device *ndev, enum can_mode mode)
        /* bring the bus online */
        ret = ican3_set_bus_state(mod, true);
        if (ret) {
-               dev_err(mod->dev, "unable to set bus-on\n");
+               netdev_err(ndev, "unable to set bus-on\n");
                return ret;
        }
 
@@ -1682,7 +1679,7 @@ static int ican3_get_berr_counter(const struct net_device *ndev,
 
        ret = wait_for_completion_timeout(&mod->buserror_comp, HZ);
        if (ret == 0) {
-               dev_info(mod->dev, "%s timed out\n", __func__);
+               netdev_info(mod->ndev, "%s timed out\n", __func__);
                return -ETIMEDOUT;
        }
 
@@ -1708,7 +1705,7 @@ static ssize_t ican3_sysfs_show_term(struct device *dev,
 
        ret = wait_for_completion_timeout(&mod->termination_comp, HZ);
        if (ret == 0) {
-               dev_info(mod->dev, "%s timed out\n", __func__);
+               netdev_info(mod->ndev, "%s timed out\n", __func__);
                return -ETIMEDOUT;
        }
 
@@ -1778,7 +1775,6 @@ static int ican3_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, ndev);
        mod = netdev_priv(ndev);
        mod->ndev = ndev;
-       mod->dev = &pdev->dev;
        mod->num = pdata->modno;
        netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS);
        skb_queue_head_init(&mod->echoq);
index cdb9808d12dbc9883250ccceb5ac156be6a4c84d..50aa630c7dd4fdaded13a0fe558a9501ee279efe 100644 (file)
@@ -601,10 +601,10 @@ static int mcp251x_do_set_bittiming(struct net_device *net)
                          (bt->prop_seg - 1));
        mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK,
                           (bt->phase_seg2 - 1));
-       dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
-                mcp251x_read_reg(spi, CNF1),
-                mcp251x_read_reg(spi, CNF2),
-                mcp251x_read_reg(spi, CNF3));
+       dev_dbg(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
+               mcp251x_read_reg(spi, CNF1),
+               mcp251x_read_reg(spi, CNF2),
+               mcp251x_read_reg(spi, CNF3));
 
        return 0;
 }
@@ -1155,8 +1155,6 @@ static int mcp251x_can_probe(struct spi_device *spi)
 
        devm_can_led_init(net);
 
-       dev_info(&spi->dev, "probed\n");
-
        return ret;
 
 error_probe:
@@ -1197,9 +1195,7 @@ static int mcp251x_can_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-
-static int mcp251x_can_suspend(struct device *dev)
+static int __maybe_unused mcp251x_can_suspend(struct device *dev)
 {
        struct spi_device *spi = to_spi_device(dev);
        struct mcp251x_priv *priv = spi_get_drvdata(spi);
@@ -1229,7 +1225,7 @@ static int mcp251x_can_suspend(struct device *dev)
        return 0;
 }
 
-static int mcp251x_can_resume(struct device *dev)
+static int __maybe_unused mcp251x_can_resume(struct device *dev)
 {
        struct spi_device *spi = to_spi_device(dev);
        struct mcp251x_priv *priv = spi_get_drvdata(spi);
@@ -1249,7 +1245,6 @@ static int mcp251x_can_resume(struct device *dev)
        enable_irq(spi->irq);
        return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
        mcp251x_can_resume);
index 1656317c96f8898008c418f75b4020d31b0e8032..0932ffbf381b5b5c877b9988318912fcea930473 100644 (file)
@@ -63,10 +63,10 @@ static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev,
 
                dstats = per_cpu_ptr(dev->dstats, i);
                do {
-                       start = u64_stats_fetch_begin_bh(&dstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&dstats->syncp);
                        tbytes = dstats->tx_bytes;
                        tpackets = dstats->tx_packets;
-               } while (u64_stats_fetch_retry_bh(&dstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&dstats->syncp, start));
                stats->tx_bytes += tbytes;
                stats->tx_packets += tpackets;
        }
index 506b0248c4001b48382f3ef6be2ccbc47724c8fa..39484b534f5e7cf20118998d888b4f168b3765ac 100644 (file)
@@ -22,6 +22,7 @@ source "drivers/net/ethernet/adaptec/Kconfig"
 source "drivers/net/ethernet/aeroflex/Kconfig"
 source "drivers/net/ethernet/allwinner/Kconfig"
 source "drivers/net/ethernet/alteon/Kconfig"
+source "drivers/net/ethernet/altera/Kconfig"
 source "drivers/net/ethernet/amd/Kconfig"
 source "drivers/net/ethernet/apple/Kconfig"
 source "drivers/net/ethernet/arc/Kconfig"
index c0b8789952e711fb77e44fc214d06ee8cac5e8f3..adf61af507f7487ef4221f5fa121885a52f19f69 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/
 obj-$(CONFIG_GRETH) += aeroflex/
 obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/
 obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
+obj-$(CONFIG_ALTERA_TSE) += altera/
 obj-$(CONFIG_NET_VENDOR_AMD) += amd/
 obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
 obj-$(CONFIG_NET_VENDOR_ARC) += arc/
diff --git a/drivers/net/ethernet/altera/Kconfig b/drivers/net/ethernet/altera/Kconfig
new file mode 100644 (file)
index 0000000..80c1ab7
--- /dev/null
@@ -0,0 +1,8 @@
+config ALTERA_TSE
+       tristate "Altera Triple-Speed Ethernet MAC support"
+       select PHYLIB
+       ---help---
+         This driver supports the Altera Triple-Speed (TSE) Ethernet MAC.
+
+         To compile this driver as a module, choose M here. The module
+         will be called alteratse.
diff --git a/drivers/net/ethernet/altera/Makefile b/drivers/net/ethernet/altera/Makefile
new file mode 100644 (file)
index 0000000..d4a187e
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the Altera device drivers.
+#
+
+obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
+altera_tse-objs := altera_tse_main.o altera_tse_ethtool.o \
+altera_msgdma.o altera_sgdma.o altera_utils.o
diff --git a/drivers/net/ethernet/altera/altera_msgdma.c b/drivers/net/ethernet/altera/altera_msgdma.c
new file mode 100644 (file)
index 0000000..3df1866
--- /dev/null
@@ -0,0 +1,202 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * 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/>.
+ */
+
+#include <linux/netdevice.h>
+#include "altera_utils.h"
+#include "altera_tse.h"
+#include "altera_msgdmahw.h"
+
+/* No initialization work to do for MSGDMA */
+int msgdma_initialize(struct altera_tse_private *priv)
+{
+       return 0;
+}
+
+void msgdma_uninitialize(struct altera_tse_private *priv)
+{
+}
+
+void msgdma_reset(struct altera_tse_private *priv)
+{
+       int counter;
+       struct msgdma_csr *txcsr =
+               (struct msgdma_csr *)priv->tx_dma_csr;
+       struct msgdma_csr *rxcsr =
+               (struct msgdma_csr *)priv->rx_dma_csr;
+
+       /* Reset Rx mSGDMA */
+       iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status);
+       iowrite32(MSGDMA_CSR_CTL_RESET, &rxcsr->control);
+
+       counter = 0;
+       while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+               if (tse_bit_is_clear(&rxcsr->status,
+                                    MSGDMA_CSR_STAT_RESETTING))
+                       break;
+               udelay(1);
+       }
+
+       if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
+               netif_warn(priv, drv, priv->dev,
+                          "TSE Rx mSGDMA resetting bit never cleared!\n");
+
+       /* clear all status bits */
+       iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status);
+
+       /* Reset Tx mSGDMA */
+       iowrite32(MSGDMA_CSR_STAT_MASK, &txcsr->status);
+       iowrite32(MSGDMA_CSR_CTL_RESET, &txcsr->control);
+
+       counter = 0;
+       while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+               if (tse_bit_is_clear(&txcsr->status,
+                                    MSGDMA_CSR_STAT_RESETTING))
+                       break;
+               udelay(1);
+       }
+
+       if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
+               netif_warn(priv, drv, priv->dev,
+                          "TSE Tx mSGDMA resetting bit never cleared!\n");
+
+       /* clear all status bits */
+       iowrite32(MSGDMA_CSR_STAT_MASK, &txcsr->status);
+}
+
+void msgdma_disable_rxirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->rx_dma_csr;
+       tse_clear_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_enable_rxirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->rx_dma_csr;
+       tse_set_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_disable_txirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->tx_dma_csr;
+       tse_clear_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_enable_txirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->tx_dma_csr;
+       tse_set_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_clear_rxirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->rx_dma_csr;
+       iowrite32(MSGDMA_CSR_STAT_IRQ, &csr->status);
+}
+
+void msgdma_clear_txirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->tx_dma_csr;
+       iowrite32(MSGDMA_CSR_STAT_IRQ, &csr->status);
+}
+
+/* return 0 to indicate transmit is pending */
+int msgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+       struct msgdma_extended_desc *desc = priv->tx_dma_desc;
+
+       iowrite32(lower_32_bits(buffer->dma_addr), &desc->read_addr_lo);
+       iowrite32(upper_32_bits(buffer->dma_addr), &desc->read_addr_hi);
+       iowrite32(0, &desc->write_addr_lo);
+       iowrite32(0, &desc->write_addr_hi);
+       iowrite32(buffer->len, &desc->len);
+       iowrite32(0, &desc->burst_seq_num);
+       iowrite32(MSGDMA_DESC_TX_STRIDE, &desc->stride);
+       iowrite32(MSGDMA_DESC_CTL_TX_SINGLE, &desc->control);
+       return 0;
+}
+
+u32 msgdma_tx_completions(struct altera_tse_private *priv)
+{
+       u32 ready = 0;
+       u32 inuse;
+       u32 status;
+       struct msgdma_csr *txcsr =
+               (struct msgdma_csr *)priv->tx_dma_csr;
+
+       /* Get number of sent descriptors */
+       inuse = ioread32(&txcsr->rw_fill_level) & 0xffff;
+
+       if (inuse) { /* Tx FIFO is not empty */
+               ready = priv->tx_prod - priv->tx_cons - inuse - 1;
+       } else {
+               /* Check for buffered last packet */
+               status = ioread32(&txcsr->status);
+               if (status & MSGDMA_CSR_STAT_BUSY)
+                       ready = priv->tx_prod - priv->tx_cons - 1;
+               else
+                       ready = priv->tx_prod - priv->tx_cons;
+       }
+       return ready;
+}
+
+/* Put buffer to the mSGDMA RX FIFO
+ */
+int msgdma_add_rx_desc(struct altera_tse_private *priv,
+                       struct tse_buffer *rxbuffer)
+{
+       struct msgdma_extended_desc *desc = priv->rx_dma_desc;
+       u32 len = priv->rx_dma_buf_sz;
+       dma_addr_t dma_addr = rxbuffer->dma_addr;
+       u32 control = (MSGDMA_DESC_CTL_END_ON_EOP
+                       | MSGDMA_DESC_CTL_END_ON_LEN
+                       | MSGDMA_DESC_CTL_TR_COMP_IRQ
+                       | MSGDMA_DESC_CTL_EARLY_IRQ
+                       | MSGDMA_DESC_CTL_TR_ERR_IRQ
+                       | MSGDMA_DESC_CTL_GO);
+
+       iowrite32(0, &desc->read_addr_lo);
+       iowrite32(0, &desc->read_addr_hi);
+       iowrite32(lower_32_bits(dma_addr), &desc->write_addr_lo);
+       iowrite32(upper_32_bits(dma_addr), &desc->write_addr_hi);
+       iowrite32(len, &desc->len);
+       iowrite32(0, &desc->burst_seq_num);
+       iowrite32(0x00010001, &desc->stride);
+       iowrite32(control, &desc->control);
+       return 1;
+}
+
+/* status is returned on upper 16 bits,
+ * length is returned in lower 16 bits
+ */
+u32 msgdma_rx_status(struct altera_tse_private *priv)
+{
+       u32 rxstatus = 0;
+       u32 pktlength;
+       u32 pktstatus;
+       struct msgdma_csr *rxcsr =
+               (struct msgdma_csr *)priv->rx_dma_csr;
+       struct msgdma_response *rxresp =
+               (struct msgdma_response *)priv->rx_dma_resp;
+
+       if (ioread32(&rxcsr->resp_fill_level) & 0xffff) {
+               pktlength = ioread32(&rxresp->bytes_transferred);
+               pktstatus = ioread32(&rxresp->status);
+               rxstatus = pktstatus;
+               rxstatus = rxstatus << 16;
+               rxstatus |= (pktlength & 0xffff);
+       }
+       return rxstatus;
+}
diff --git a/drivers/net/ethernet/altera/altera_msgdma.h b/drivers/net/ethernet/altera/altera_msgdma.h
new file mode 100644 (file)
index 0000000..7f0f5bf
--- /dev/null
@@ -0,0 +1,34 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * 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/>.
+ */
+
+#ifndef __ALTERA_MSGDMA_H__
+#define __ALTERA_MSGDMA_H__
+
+void msgdma_reset(struct altera_tse_private *);
+void msgdma_enable_txirq(struct altera_tse_private *);
+void msgdma_enable_rxirq(struct altera_tse_private *);
+void msgdma_disable_rxirq(struct altera_tse_private *);
+void msgdma_disable_txirq(struct altera_tse_private *);
+void msgdma_clear_rxirq(struct altera_tse_private *);
+void msgdma_clear_txirq(struct altera_tse_private *);
+u32 msgdma_tx_completions(struct altera_tse_private *);
+int msgdma_add_rx_desc(struct altera_tse_private *, struct tse_buffer *);
+int msgdma_tx_buffer(struct altera_tse_private *, struct tse_buffer *);
+u32 msgdma_rx_status(struct altera_tse_private *);
+int msgdma_initialize(struct altera_tse_private *);
+void msgdma_uninitialize(struct altera_tse_private *);
+
+#endif /*  __ALTERA_MSGDMA_H__ */
diff --git a/drivers/net/ethernet/altera/altera_msgdmahw.h b/drivers/net/ethernet/altera/altera_msgdmahw.h
new file mode 100644 (file)
index 0000000..d7b59ba
--- /dev/null
@@ -0,0 +1,167 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * 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/>.
+ */
+
+#ifndef __ALTERA_MSGDMAHW_H__
+#define __ALTERA_MSGDMAHW_H__
+
+/* mSGDMA standard descriptor format
+ */
+struct msgdma_desc {
+       u32 read_addr;  /* data buffer source address */
+       u32 write_addr; /* data buffer destination address */
+       u32 len;        /* the number of bytes to transfer per descriptor */
+       u32 control;    /* characteristics of the transfer */
+};
+
+/* mSGDMA extended descriptor format
+ */
+struct msgdma_extended_desc {
+       u32 read_addr_lo;       /* data buffer source address low bits */
+       u32 write_addr_lo;      /* data buffer destination address low bits */
+       u32 len;                /* the number of bytes to transfer
+                                * per descriptor
+                                */
+       u32 burst_seq_num;      /* bit 31:24 write burst
+                                * bit 23:16 read burst
+                                * bit 15:0  sequence number
+                                */
+       u32 stride;             /* bit 31:16 write stride
+                                * bit 15:0  read stride
+                                */
+       u32 read_addr_hi;       /* data buffer source address high bits */
+       u32 write_addr_hi;      /* data buffer destination address high bits */
+       u32 control;            /* characteristics of the transfer */
+};
+
+/* mSGDMA descriptor control field bit definitions
+ */
+#define MSGDMA_DESC_CTL_SET_CH(x)      ((x) & 0xff)
+#define MSGDMA_DESC_CTL_GEN_SOP                BIT(8)
+#define MSGDMA_DESC_CTL_GEN_EOP                BIT(9)
+#define MSGDMA_DESC_CTL_PARK_READS     BIT(10)
+#define MSGDMA_DESC_CTL_PARK_WRITES    BIT(11)
+#define MSGDMA_DESC_CTL_END_ON_EOP     BIT(12)
+#define MSGDMA_DESC_CTL_END_ON_LEN     BIT(13)
+#define MSGDMA_DESC_CTL_TR_COMP_IRQ    BIT(14)
+#define MSGDMA_DESC_CTL_EARLY_IRQ      BIT(15)
+#define MSGDMA_DESC_CTL_TR_ERR_IRQ     (0xff << 16)
+#define MSGDMA_DESC_CTL_EARLY_DONE     BIT(24)
+/* Writing â€˜1’ to the â€˜go’ bit commits the entire descriptor into the
+ * descriptor FIFO(s)
+ */
+#define MSGDMA_DESC_CTL_GO             BIT(31)
+
+/* Tx buffer control flags
+ */
+#define MSGDMA_DESC_CTL_TX_FIRST       (MSGDMA_DESC_CTL_GEN_SOP |      \
+                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_TX_MIDDLE      (MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_TX_LAST                (MSGDMA_DESC_CTL_GEN_EOP |      \
+                                        MSGDMA_DESC_CTL_TR_COMP_IRQ |  \
+                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_TX_SINGLE      (MSGDMA_DESC_CTL_GEN_SOP |      \
+                                        MSGDMA_DESC_CTL_GEN_EOP |      \
+                                        MSGDMA_DESC_CTL_TR_COMP_IRQ |  \
+                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_RX_SINGLE      (MSGDMA_DESC_CTL_END_ON_EOP |   \
+                                        MSGDMA_DESC_CTL_END_ON_LEN |   \
+                                        MSGDMA_DESC_CTL_TR_COMP_IRQ |  \
+                                        MSGDMA_DESC_CTL_EARLY_IRQ |    \
+                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+/* mSGDMA extended descriptor stride definitions
+ */
+#define MSGDMA_DESC_TX_STRIDE          (0x00010001)
+#define MSGDMA_DESC_RX_STRIDE          (0x00010001)
+
+/* mSGDMA dispatcher control and status register map
+ */
+struct msgdma_csr {
+       u32 status;             /* Read/Clear */
+       u32 control;            /* Read/Write */
+       u32 rw_fill_level;      /* bit 31:16 - write fill level
+                                * bit 15:0  - read fill level
+                                */
+       u32 resp_fill_level;    /* bit 15:0 */
+       u32 rw_seq_num;         /* bit 31:16 - write sequence number
+                                * bit 15:0  - read sequence number
+                                */
+       u32 pad[3];             /* reserved */
+};
+
+/* mSGDMA CSR status register bit definitions
+ */
+#define MSGDMA_CSR_STAT_BUSY                   BIT(0)
+#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY         BIT(1)
+#define MSGDMA_CSR_STAT_DESC_BUF_FULL          BIT(2)
+#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY         BIT(3)
+#define MSGDMA_CSR_STAT_RESP_BUF_FULL          BIT(4)
+#define MSGDMA_CSR_STAT_STOPPED                        BIT(5)
+#define MSGDMA_CSR_STAT_RESETTING              BIT(6)
+#define MSGDMA_CSR_STAT_STOPPED_ON_ERR         BIT(7)
+#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY       BIT(8)
+#define MSGDMA_CSR_STAT_IRQ                    BIT(9)
+#define MSGDMA_CSR_STAT_MASK                   0x3FF
+#define MSGDMA_CSR_STAT_MASK_WITHOUT_IRQ       0x1FF
+
+#define MSGDMA_CSR_STAT_BUSY_GET(v)                    GET_BIT_VALUE(v, 0)
+#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY_GET(v)          GET_BIT_VALUE(v, 1)
+#define MSGDMA_CSR_STAT_DESC_BUF_FULL_GET(v)           GET_BIT_VALUE(v, 2)
+#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY_GET(v)          GET_BIT_VALUE(v, 3)
+#define MSGDMA_CSR_STAT_RESP_BUF_FULL_GET(v)           GET_BIT_VALUE(v, 4)
+#define MSGDMA_CSR_STAT_STOPPED_GET(v)                 GET_BIT_VALUE(v, 5)
+#define MSGDMA_CSR_STAT_RESETTING_GET(v)               GET_BIT_VALUE(v, 6)
+#define MSGDMA_CSR_STAT_STOPPED_ON_ERR_GET(v)          GET_BIT_VALUE(v, 7)
+#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY_GET(v)                GET_BIT_VALUE(v, 8)
+#define MSGDMA_CSR_STAT_IRQ_GET(v)                     GET_BIT_VALUE(v, 9)
+
+/* mSGDMA CSR control register bit definitions
+ */
+#define MSGDMA_CSR_CTL_STOP                    BIT(0)
+#define MSGDMA_CSR_CTL_RESET                   BIT(1)
+#define MSGDMA_CSR_CTL_STOP_ON_ERR             BIT(2)
+#define MSGDMA_CSR_CTL_STOP_ON_EARLY           BIT(3)
+#define MSGDMA_CSR_CTL_GLOBAL_INTR             BIT(4)
+#define MSGDMA_CSR_CTL_STOP_DESCS              BIT(5)
+
+/* mSGDMA CSR fill level bits
+ */
+#define MSGDMA_CSR_WR_FILL_LEVEL_GET(v)                (((v) & 0xffff0000) >> 16)
+#define MSGDMA_CSR_RD_FILL_LEVEL_GET(v)                ((v) & 0x0000ffff)
+#define MSGDMA_CSR_RESP_FILL_LEVEL_GET(v)      ((v) & 0x0000ffff)
+
+/* mSGDMA response register map
+ */
+struct msgdma_response {
+       u32 bytes_transferred;
+       u32 status;
+};
+
+/* mSGDMA response register bit definitions
+ */
+#define MSGDMA_RESP_EARLY_TERM BIT(8)
+#define MSGDMA_RESP_ERR_MASK   0xFF
+
+#endif /* __ALTERA_MSGDMA_H__*/
diff --git a/drivers/net/ethernet/altera/altera_sgdma.c b/drivers/net/ethernet/altera/altera_sgdma.c
new file mode 100644 (file)
index 0000000..cbeee07
--- /dev/null
@@ -0,0 +1,511 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * 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/>.
+ */
+
+#include <linux/list.h>
+#include "altera_utils.h"
+#include "altera_tse.h"
+#include "altera_sgdmahw.h"
+#include "altera_sgdma.h"
+
+static void sgdma_descrip(struct sgdma_descrip *desc,
+                         struct sgdma_descrip *ndesc,
+                         dma_addr_t ndesc_phys,
+                         dma_addr_t raddr,
+                         dma_addr_t waddr,
+                         u16 length,
+                         int generate_eop,
+                         int rfixed,
+                         int wfixed);
+
+static int sgdma_async_write(struct altera_tse_private *priv,
+                             struct sgdma_descrip *desc);
+
+static int sgdma_async_read(struct altera_tse_private *priv);
+
+static dma_addr_t
+sgdma_txphysaddr(struct altera_tse_private *priv,
+                struct sgdma_descrip *desc);
+
+static dma_addr_t
+sgdma_rxphysaddr(struct altera_tse_private *priv,
+                struct sgdma_descrip *desc);
+
+static int sgdma_txbusy(struct altera_tse_private *priv);
+
+static int sgdma_rxbusy(struct altera_tse_private *priv);
+
+static void
+queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer);
+
+static void
+queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer);
+
+static struct tse_buffer *
+dequeue_tx(struct altera_tse_private *priv);
+
+static struct tse_buffer *
+dequeue_rx(struct altera_tse_private *priv);
+
+static struct tse_buffer *
+queue_rx_peekhead(struct altera_tse_private *priv);
+
+int sgdma_initialize(struct altera_tse_private *priv)
+{
+       priv->txctrlreg = SGDMA_CTRLREG_ILASTD;
+
+       priv->rxctrlreg = SGDMA_CTRLREG_IDESCRIP |
+                     SGDMA_CTRLREG_ILASTD;
+
+       INIT_LIST_HEAD(&priv->txlisthd);
+       INIT_LIST_HEAD(&priv->rxlisthd);
+
+       priv->rxdescphys = (dma_addr_t) 0;
+       priv->txdescphys = (dma_addr_t) 0;
+
+       priv->rxdescphys = dma_map_single(priv->device, priv->rx_dma_desc,
+                                         priv->rxdescmem, DMA_BIDIRECTIONAL);
+
+       if (dma_mapping_error(priv->device, priv->rxdescphys)) {
+               sgdma_uninitialize(priv);
+               netdev_err(priv->dev, "error mapping rx descriptor memory\n");
+               return -EINVAL;
+       }
+
+       priv->txdescphys = dma_map_single(priv->device, priv->rx_dma_desc,
+                                         priv->rxdescmem, DMA_TO_DEVICE);
+
+       if (dma_mapping_error(priv->device, priv->txdescphys)) {
+               sgdma_uninitialize(priv);
+               netdev_err(priv->dev, "error mapping tx descriptor memory\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void sgdma_uninitialize(struct altera_tse_private *priv)
+{
+       if (priv->rxdescphys)
+               dma_unmap_single(priv->device, priv->rxdescphys,
+                                priv->rxdescmem, DMA_BIDIRECTIONAL);
+
+       if (priv->txdescphys)
+               dma_unmap_single(priv->device, priv->txdescphys,
+                                priv->txdescmem, DMA_TO_DEVICE);
+}
+
+/* This function resets the SGDMA controller and clears the
+ * descriptor memory used for transmits and receives.
+ */
+void sgdma_reset(struct altera_tse_private *priv)
+{
+       u32 *ptxdescripmem = (u32 *)priv->tx_dma_desc;
+       u32 txdescriplen   = priv->txdescmem;
+       u32 *prxdescripmem = (u32 *)priv->rx_dma_desc;
+       u32 rxdescriplen   = priv->rxdescmem;
+       struct sgdma_csr *ptxsgdma = (struct sgdma_csr *)priv->tx_dma_csr;
+       struct sgdma_csr *prxsgdma = (struct sgdma_csr *)priv->rx_dma_csr;
+
+       /* Initialize descriptor memory to 0 */
+       memset(ptxdescripmem, 0, txdescriplen);
+       memset(prxdescripmem, 0, rxdescriplen);
+
+       iowrite32(SGDMA_CTRLREG_RESET, &ptxsgdma->control);
+       iowrite32(0, &ptxsgdma->control);
+
+       iowrite32(SGDMA_CTRLREG_RESET, &prxsgdma->control);
+       iowrite32(0, &prxsgdma->control);
+}
+
+void sgdma_enable_rxirq(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       priv->rxctrlreg |= SGDMA_CTRLREG_INTEN;
+       tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN);
+}
+
+void sgdma_enable_txirq(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+       priv->txctrlreg |= SGDMA_CTRLREG_INTEN;
+       tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN);
+}
+
+/* for SGDMA, RX interrupts remain enabled after enabling */
+void sgdma_disable_rxirq(struct altera_tse_private *priv)
+{
+}
+
+/* for SGDMA, TX interrupts remain enabled after enabling */
+void sgdma_disable_txirq(struct altera_tse_private *priv)
+{
+}
+
+void sgdma_clear_rxirq(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT);
+}
+
+void sgdma_clear_txirq(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+       tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT);
+}
+
+/* transmits buffer through SGDMA. Returns number of buffers
+ * transmitted, 0 if not possible.
+ *
+ * tx_lock is held by the caller
+ */
+int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+       int pktstx = 0;
+       struct sgdma_descrip *descbase =
+               (struct sgdma_descrip *)priv->tx_dma_desc;
+
+       struct sgdma_descrip *cdesc = &descbase[0];
+       struct sgdma_descrip *ndesc = &descbase[1];
+
+       /* wait 'til the tx sgdma is ready for the next transmit request */
+       if (sgdma_txbusy(priv))
+               return 0;
+
+       sgdma_descrip(cdesc,                    /* current descriptor */
+                     ndesc,                    /* next descriptor */
+                     sgdma_txphysaddr(priv, ndesc),
+                     buffer->dma_addr,         /* address of packet to xmit */
+                     0,                        /* write addr 0 for tx dma */
+                     buffer->len,              /* length of packet */
+                     SGDMA_CONTROL_EOP,        /* Generate EOP */
+                     0,                        /* read fixed */
+                     SGDMA_CONTROL_WR_FIXED);  /* Generate SOP */
+
+       pktstx = sgdma_async_write(priv, cdesc);
+
+       /* enqueue the request to the pending transmit queue */
+       queue_tx(priv, buffer);
+
+       return 1;
+}
+
+
+/* tx_lock held to protect access to queued tx list
+ */
+u32 sgdma_tx_completions(struct altera_tse_private *priv)
+{
+       u32 ready = 0;
+       struct sgdma_descrip *desc = (struct sgdma_descrip *)priv->tx_dma_desc;
+
+       if (!sgdma_txbusy(priv) &&
+           ((desc->control & SGDMA_CONTROL_HW_OWNED) == 0) &&
+           (dequeue_tx(priv))) {
+               ready = 1;
+       }
+
+       return ready;
+}
+
+int sgdma_add_rx_desc(struct altera_tse_private *priv,
+                     struct tse_buffer *rxbuffer)
+{
+       queue_rx(priv, rxbuffer);
+       return sgdma_async_read(priv);
+}
+
+/* status is returned on upper 16 bits,
+ * length is returned in lower 16 bits
+ */
+u32 sgdma_rx_status(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       struct sgdma_descrip *base = (struct sgdma_descrip *)priv->rx_dma_desc;
+       struct sgdma_descrip *desc = NULL;
+       int pktsrx;
+       unsigned int rxstatus = 0;
+       unsigned int pktlength = 0;
+       unsigned int pktstatus = 0;
+       struct tse_buffer *rxbuffer = NULL;
+
+       dma_sync_single_for_cpu(priv->device,
+                               priv->rxdescphys,
+                               priv->rxdescmem,
+                               DMA_BIDIRECTIONAL);
+
+       desc = &base[0];
+       if ((ioread32(&csr->status) & SGDMA_STSREG_EOP) ||
+           (desc->status & SGDMA_STATUS_EOP)) {
+               pktlength = desc->bytes_xferred;
+               pktstatus = desc->status & 0x3f;
+               rxstatus = pktstatus;
+               rxstatus = rxstatus << 16;
+               rxstatus |= (pktlength & 0xffff);
+
+               desc->status = 0;
+
+               rxbuffer = dequeue_rx(priv);
+               if (rxbuffer == NULL)
+                       netdev_err(priv->dev,
+                                  "sgdma rx and rx queue empty!\n");
+
+               /* kick the rx sgdma after reaping this descriptor */
+               pktsrx = sgdma_async_read(priv);
+       }
+
+       return rxstatus;
+}
+
+
+/* Private functions */
+static void sgdma_descrip(struct sgdma_descrip *desc,
+                         struct sgdma_descrip *ndesc,
+                         dma_addr_t ndesc_phys,
+                         dma_addr_t raddr,
+                         dma_addr_t waddr,
+                         u16 length,
+                         int generate_eop,
+                         int rfixed,
+                         int wfixed)
+{
+       /* Clear the next descriptor as not owned by hardware */
+       u32 ctrl = ndesc->control;
+       ctrl &= ~SGDMA_CONTROL_HW_OWNED;
+       ndesc->control = ctrl;
+
+       ctrl = 0;
+       ctrl = SGDMA_CONTROL_HW_OWNED;
+       ctrl |= generate_eop;
+       ctrl |= rfixed;
+       ctrl |= wfixed;
+
+       /* Channel is implicitly zero, initialized to 0 by default */
+
+       desc->raddr = raddr;
+       desc->waddr = waddr;
+       desc->next = lower_32_bits(ndesc_phys);
+       desc->control = ctrl;
+       desc->status = 0;
+       desc->rburst = 0;
+       desc->wburst = 0;
+       desc->bytes = length;
+       desc->bytes_xferred = 0;
+}
+
+/* If hardware is busy, don't restart async read.
+ * if status register is 0 - meaning initial state, restart async read,
+ * probably for the first time when populating a receive buffer.
+ * If read status indicate not busy and a status, restart the async
+ * DMA read.
+ */
+static int sgdma_async_read(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       struct sgdma_descrip *descbase =
+               (struct sgdma_descrip *)priv->rx_dma_desc;
+
+       struct sgdma_descrip *cdesc = &descbase[0];
+       struct sgdma_descrip *ndesc = &descbase[1];
+
+       unsigned int sts = ioread32(&csr->status);
+       struct tse_buffer *rxbuffer = NULL;
+
+       if (!sgdma_rxbusy(priv)) {
+               rxbuffer = queue_rx_peekhead(priv);
+               if (rxbuffer == NULL)
+                       return 0;
+
+               sgdma_descrip(cdesc,            /* current descriptor */
+                             ndesc,            /* next descriptor */
+                             sgdma_rxphysaddr(priv, ndesc),
+                             0,                /* read addr 0 for rx dma */
+                             rxbuffer->dma_addr, /* write addr for rx dma */
+                             0,                /* read 'til EOP */
+                             0,                /* EOP: NA for rx dma */
+                             0,                /* read fixed: NA for rx dma */
+                             0);               /* SOP: NA for rx DMA */
+
+               /* clear control and status */
+               iowrite32(0, &csr->control);
+
+               /* If statuc available, clear those bits */
+               if (sts & 0xf)
+                       iowrite32(0xf, &csr->status);
+
+               dma_sync_single_for_device(priv->device,
+                                          priv->rxdescphys,
+                                          priv->rxdescmem,
+                                          DMA_BIDIRECTIONAL);
+
+               iowrite32(lower_32_bits(sgdma_rxphysaddr(priv, cdesc)),
+                         &csr->next_descrip);
+
+               iowrite32((priv->rxctrlreg | SGDMA_CTRLREG_START),
+                         &csr->control);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static int sgdma_async_write(struct altera_tse_private *priv,
+                            struct sgdma_descrip *desc)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+
+       if (sgdma_txbusy(priv))
+               return 0;
+
+       /* clear control and status */
+       iowrite32(0, &csr->control);
+       iowrite32(0x1f, &csr->status);
+
+       dma_sync_single_for_device(priv->device, priv->txdescphys,
+                                  priv->txdescmem, DMA_TO_DEVICE);
+
+       iowrite32(lower_32_bits(sgdma_txphysaddr(priv, desc)),
+                 &csr->next_descrip);
+
+       iowrite32((priv->txctrlreg | SGDMA_CTRLREG_START),
+                 &csr->control);
+
+       return 1;
+}
+
+static dma_addr_t
+sgdma_txphysaddr(struct altera_tse_private *priv,
+                struct sgdma_descrip *desc)
+{
+       dma_addr_t paddr = priv->txdescmem_busaddr;
+       dma_addr_t offs = (dma_addr_t)((dma_addr_t)desc -
+                               (dma_addr_t)priv->tx_dma_desc);
+       return paddr + offs;
+}
+
+static dma_addr_t
+sgdma_rxphysaddr(struct altera_tse_private *priv,
+                struct sgdma_descrip *desc)
+{
+       dma_addr_t paddr = priv->rxdescmem_busaddr;
+       dma_addr_t offs = (dma_addr_t)((dma_addr_t)desc -
+                               (dma_addr_t)priv->rx_dma_desc);
+       return paddr + offs;
+}
+
+#define list_remove_head(list, entry, type, member)                    \
+       do {                                                            \
+               entry = NULL;                                           \
+               if (!list_empty(list)) {                                \
+                       entry = list_entry((list)->next, type, member); \
+                       list_del_init(&entry->member);                  \
+               }                                                       \
+       } while (0)
+
+#define list_peek_head(list, entry, type, member)                      \
+       do {                                                            \
+               entry = NULL;                                           \
+               if (!list_empty(list)) {                                \
+                       entry = list_entry((list)->next, type, member); \
+               }                                                       \
+       } while (0)
+
+/* adds a tse_buffer to the tail of a tx buffer list.
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static void
+queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+       list_add_tail(&buffer->lh, &priv->txlisthd);
+}
+
+
+/* adds a tse_buffer to the tail of a rx buffer list
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static void
+queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+       list_add_tail(&buffer->lh, &priv->rxlisthd);
+}
+
+/* dequeues a tse_buffer from the transmit buffer list, otherwise
+ * returns NULL if empty.
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static struct tse_buffer *
+dequeue_tx(struct altera_tse_private *priv)
+{
+       struct tse_buffer *buffer = NULL;
+       list_remove_head(&priv->txlisthd, buffer, struct tse_buffer, lh);
+       return buffer;
+}
+
+/* dequeues a tse_buffer from the receive buffer list, otherwise
+ * returns NULL if empty
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static struct tse_buffer *
+dequeue_rx(struct altera_tse_private *priv)
+{
+       struct tse_buffer *buffer = NULL;
+       list_remove_head(&priv->rxlisthd, buffer, struct tse_buffer, lh);
+       return buffer;
+}
+
+/* dequeues a tse_buffer from the receive buffer list, otherwise
+ * returns NULL if empty
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list while the
+ * head is being examined.
+ */
+static struct tse_buffer *
+queue_rx_peekhead(struct altera_tse_private *priv)
+{
+       struct tse_buffer *buffer = NULL;
+       list_peek_head(&priv->rxlisthd, buffer, struct tse_buffer, lh);
+       return buffer;
+}
+
+/* check and return rx sgdma status without polling
+ */
+static int sgdma_rxbusy(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       return ioread32(&csr->status) & SGDMA_STSREG_BUSY;
+}
+
+/* waits for the tx sgdma to finish it's current operation, returns 0
+ * when it transitions to nonbusy, returns 1 if the operation times out
+ */
+static int sgdma_txbusy(struct altera_tse_private *priv)
+{
+       int delay = 0;
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+
+       /* if DMA is busy, wait for current transactino to finish */
+       while ((ioread32(&csr->status) & SGDMA_STSREG_BUSY) && (delay++ < 100))
+               udelay(1);
+
+       if (ioread32(&csr->status) & SGDMA_STSREG_BUSY) {
+               netdev_err(priv->dev, "timeout waiting for tx dma\n");
+               return 1;
+       }
+       return 0;
+}
diff --git a/drivers/net/ethernet/altera/altera_sgdma.h b/drivers/net/ethernet/altera/altera_sgdma.h
new file mode 100644 (file)
index 0000000..07d4717
--- /dev/null
@@ -0,0 +1,35 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * 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/>.
+ */
+
+#ifndef __ALTERA_SGDMA_H__
+#define __ALTERA_SGDMA_H__
+
+void sgdma_reset(struct altera_tse_private *);
+void sgdma_enable_txirq(struct altera_tse_private *);
+void sgdma_enable_rxirq(struct altera_tse_private *);
+void sgdma_disable_rxirq(struct altera_tse_private *);
+void sgdma_disable_txirq(struct altera_tse_private *);
+void sgdma_clear_rxirq(struct altera_tse_private *);
+void sgdma_clear_txirq(struct altera_tse_private *);
+int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *);
+u32 sgdma_tx_completions(struct altera_tse_private *);
+int sgdma_add_rx_desc(struct altera_tse_private *priv, struct tse_buffer *);
+void sgdma_status(struct altera_tse_private *);
+u32 sgdma_rx_status(struct altera_tse_private *);
+int sgdma_initialize(struct altera_tse_private *);
+void sgdma_uninitialize(struct altera_tse_private *);
+
+#endif /*  __ALTERA_SGDMA_H__ */
diff --git a/drivers/net/ethernet/altera/altera_sgdmahw.h b/drivers/net/ethernet/altera/altera_sgdmahw.h
new file mode 100644 (file)
index 0000000..ba3334f
--- /dev/null
@@ -0,0 +1,124 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * 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/>.
+ */
+
+#ifndef __ALTERA_SGDMAHW_H__
+#define __ALTERA_SGDMAHW_H__
+
+/* SGDMA descriptor structure */
+struct sgdma_descrip {
+       unsigned int    raddr; /* address of data to be read */
+       unsigned int    pad1;
+       unsigned int    waddr;
+       unsigned int    pad2;
+       unsigned int    next;
+       unsigned int    pad3;
+       unsigned short  bytes;
+       unsigned char   rburst;
+       unsigned char   wburst;
+       unsigned short  bytes_xferred;  /* 16 bits, bytes xferred */
+
+       /* bit 0: error
+        * bit 1: length error
+        * bit 2: crc error
+        * bit 3: truncated error
+        * bit 4: phy error
+        * bit 5: collision error
+        * bit 6: reserved
+        * bit 7: status eop for recv case
+        */
+       unsigned char   status;
+
+       /* bit 0: eop
+        * bit 1: read_fixed
+        * bit 2: write fixed
+        * bits 3,4,5,6: Channel (always 0)
+        * bit 7: hardware owned
+        */
+       unsigned char   control;
+} __packed;
+
+
+#define SGDMA_STATUS_ERR               BIT(0)
+#define SGDMA_STATUS_LENGTH_ERR                BIT(1)
+#define SGDMA_STATUS_CRC_ERR           BIT(2)
+#define SGDMA_STATUS_TRUNC_ERR         BIT(3)
+#define SGDMA_STATUS_PHY_ERR           BIT(4)
+#define SGDMA_STATUS_COLL_ERR          BIT(5)
+#define SGDMA_STATUS_EOP               BIT(7)
+
+#define SGDMA_CONTROL_EOP              BIT(0)
+#define SGDMA_CONTROL_RD_FIXED         BIT(1)
+#define SGDMA_CONTROL_WR_FIXED         BIT(2)
+
+/* Channel is always 0, so just zero initialize it */
+
+#define SGDMA_CONTROL_HW_OWNED         BIT(7)
+
+/* SGDMA register space */
+struct sgdma_csr {
+       /* bit 0: error
+        * bit 1: eop
+        * bit 2: descriptor completed
+        * bit 3: chain completed
+        * bit 4: busy
+        * remainder reserved
+        */
+       u32     status;
+       u32     pad1[3];
+
+       /* bit 0: interrupt on error
+        * bit 1: interrupt on eop
+        * bit 2: interrupt after every descriptor
+        * bit 3: interrupt after last descrip in a chain
+        * bit 4: global interrupt enable
+        * bit 5: starts descriptor processing
+        * bit 6: stop core on dma error
+        * bit 7: interrupt on max descriptors
+        * bits 8-15: max descriptors to generate interrupt
+        * bit 16: Software reset
+        * bit 17: clears owned by hardware if 0, does not clear otherwise
+        * bit 18: enables descriptor polling mode
+        * bit 19-26: clocks before polling again
+        * bit 27-30: reserved
+        * bit 31: clear interrupt
+        */
+       u32     control;
+       u32     pad2[3];
+       u32     next_descrip;
+       u32     pad3[3];
+};
+
+
+#define SGDMA_STSREG_ERR       BIT(0) /* Error */
+#define SGDMA_STSREG_EOP       BIT(1) /* EOP */
+#define SGDMA_STSREG_DESCRIP   BIT(2) /* Descriptor completed */
+#define SGDMA_STSREG_CHAIN     BIT(3) /* Chain completed */
+#define SGDMA_STSREG_BUSY      BIT(4) /* Controller busy */
+
+#define SGDMA_CTRLREG_IOE      BIT(0) /* Interrupt on error */
+#define SGDMA_CTRLREG_IOEOP    BIT(1) /* Interrupt on EOP */
+#define SGDMA_CTRLREG_IDESCRIP BIT(2) /* Interrupt after every descriptor */
+#define SGDMA_CTRLREG_ILASTD   BIT(3) /* Interrupt after last descriptor */
+#define SGDMA_CTRLREG_INTEN    BIT(4) /* Global Interrupt enable */
+#define SGDMA_CTRLREG_START    BIT(5) /* starts descriptor processing */
+#define SGDMA_CTRLREG_STOPERR  BIT(6) /* stop on dma error */
+#define SGDMA_CTRLREG_INTMAX   BIT(7) /* Interrupt on max descriptors */
+#define SGDMA_CTRLREG_RESET    BIT(16)/* Software reset */
+#define SGDMA_CTRLREG_COBHW    BIT(17)/* Clears owned by hardware */
+#define SGDMA_CTRLREG_POLL     BIT(18)/* enables descriptor polling mode */
+#define SGDMA_CTRLREG_CLRINT   BIT(31)/* Clears interrupt */
+
+#endif /* __ALTERA_SGDMAHW_H__ */
diff --git a/drivers/net/ethernet/altera/altera_tse.h b/drivers/net/ethernet/altera/altera_tse.h
new file mode 100644 (file)
index 0000000..8feeed0
--- /dev/null
@@ -0,0 +1,486 @@
+/* Altera Triple-Speed Ethernet MAC driver
+ * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
+ *
+ * Contributors:
+ *   Dalon Westergreen
+ *   Thomas Chou
+ *   Ian Abbott
+ *   Yuriy Kozlov
+ *   Tobias Klauser
+ *   Andriy Smolskyy
+ *   Roman Bulgakov
+ *   Dmytro Mytarchuk
+ *   Matthew Gerlach
+ *
+ * Original driver contributed by SLS.
+ * Major updates contributed by GlobalLogic
+ *
+ * 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/>.
+ */
+
+#ifndef __ALTERA_TSE_H__
+#define __ALTERA_TSE_H__
+
+#define ALTERA_TSE_RESOURCE_NAME       "altera_tse"
+
+#include <linux/bitops.h>
+#include <linux/if_vlan.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#define ALTERA_TSE_SW_RESET_WATCHDOG_CNTR      10000
+#define ALTERA_TSE_MAC_FIFO_WIDTH              4       /* TX/RX FIFO width in
+                                                        * bytes
+                                                        */
+/* Rx FIFO default settings */
+#define ALTERA_TSE_RX_SECTION_EMPTY    16
+#define ALTERA_TSE_RX_SECTION_FULL     0
+#define ALTERA_TSE_RX_ALMOST_EMPTY     8
+#define ALTERA_TSE_RX_ALMOST_FULL      8
+
+/* Tx FIFO default settings */
+#define ALTERA_TSE_TX_SECTION_EMPTY    16
+#define ALTERA_TSE_TX_SECTION_FULL     0
+#define ALTERA_TSE_TX_ALMOST_EMPTY     8
+#define ALTERA_TSE_TX_ALMOST_FULL      3
+
+/* MAC function configuration default settings */
+#define ALTERA_TSE_TX_IPG_LENGTH       12
+
+#define GET_BIT_VALUE(v, bit)          (((v) >> (bit)) & 0x1)
+
+/* MAC Command_Config Register Bit Definitions
+ */
+#define MAC_CMDCFG_TX_ENA                      BIT(0)
+#define MAC_CMDCFG_RX_ENA                      BIT(1)
+#define MAC_CMDCFG_XON_GEN                     BIT(2)
+#define MAC_CMDCFG_ETH_SPEED                   BIT(3)
+#define MAC_CMDCFG_PROMIS_EN                   BIT(4)
+#define MAC_CMDCFG_PAD_EN                      BIT(5)
+#define MAC_CMDCFG_CRC_FWD                     BIT(6)
+#define MAC_CMDCFG_PAUSE_FWD                   BIT(7)
+#define MAC_CMDCFG_PAUSE_IGNORE                        BIT(8)
+#define MAC_CMDCFG_TX_ADDR_INS                 BIT(9)
+#define MAC_CMDCFG_HD_ENA                      BIT(10)
+#define MAC_CMDCFG_EXCESS_COL                  BIT(11)
+#define MAC_CMDCFG_LATE_COL                    BIT(12)
+#define MAC_CMDCFG_SW_RESET                    BIT(13)
+#define MAC_CMDCFG_MHASH_SEL                   BIT(14)
+#define MAC_CMDCFG_LOOP_ENA                    BIT(15)
+#define MAC_CMDCFG_TX_ADDR_SEL(v)              (((v) & 0x7) << 16)
+#define MAC_CMDCFG_MAGIC_ENA                   BIT(19)
+#define MAC_CMDCFG_SLEEP                       BIT(20)
+#define MAC_CMDCFG_WAKEUP                      BIT(21)
+#define MAC_CMDCFG_XOFF_GEN                    BIT(22)
+#define MAC_CMDCFG_CNTL_FRM_ENA                        BIT(23)
+#define MAC_CMDCFG_NO_LGTH_CHECK               BIT(24)
+#define MAC_CMDCFG_ENA_10                      BIT(25)
+#define MAC_CMDCFG_RX_ERR_DISC                 BIT(26)
+#define MAC_CMDCFG_DISABLE_READ_TIMEOUT                BIT(27)
+#define MAC_CMDCFG_CNT_RESET                   BIT(31)
+
+#define MAC_CMDCFG_TX_ENA_GET(v)               GET_BIT_VALUE(v, 0)
+#define MAC_CMDCFG_RX_ENA_GET(v)               GET_BIT_VALUE(v, 1)
+#define MAC_CMDCFG_XON_GEN_GET(v)              GET_BIT_VALUE(v, 2)
+#define MAC_CMDCFG_ETH_SPEED_GET(v)            GET_BIT_VALUE(v, 3)
+#define MAC_CMDCFG_PROMIS_EN_GET(v)            GET_BIT_VALUE(v, 4)
+#define MAC_CMDCFG_PAD_EN_GET(v)               GET_BIT_VALUE(v, 5)
+#define MAC_CMDCFG_CRC_FWD_GET(v)              GET_BIT_VALUE(v, 6)
+#define MAC_CMDCFG_PAUSE_FWD_GET(v)            GET_BIT_VALUE(v, 7)
+#define MAC_CMDCFG_PAUSE_IGNORE_GET(v)         GET_BIT_VALUE(v, 8)
+#define MAC_CMDCFG_TX_ADDR_INS_GET(v)          GET_BIT_VALUE(v, 9)
+#define MAC_CMDCFG_HD_ENA_GET(v)               GET_BIT_VALUE(v, 10)
+#define MAC_CMDCFG_EXCESS_COL_GET(v)           GET_BIT_VALUE(v, 11)
+#define MAC_CMDCFG_LATE_COL_GET(v)             GET_BIT_VALUE(v, 12)
+#define MAC_CMDCFG_SW_RESET_GET(v)             GET_BIT_VALUE(v, 13)
+#define MAC_CMDCFG_MHASH_SEL_GET(v)            GET_BIT_VALUE(v, 14)
+#define MAC_CMDCFG_LOOP_ENA_GET(v)             GET_BIT_VALUE(v, 15)
+#define MAC_CMDCFG_TX_ADDR_SEL_GET(v)          (((v) >> 16) & 0x7)
+#define MAC_CMDCFG_MAGIC_ENA_GET(v)            GET_BIT_VALUE(v, 19)
+#define MAC_CMDCFG_SLEEP_GET(v)                        GET_BIT_VALUE(v, 20)
+#define MAC_CMDCFG_WAKEUP_GET(v)               GET_BIT_VALUE(v, 21)
+#define MAC_CMDCFG_XOFF_GEN_GET(v)             GET_BIT_VALUE(v, 22)
+#define MAC_CMDCFG_CNTL_FRM_ENA_GET(v)         GET_BIT_VALUE(v, 23)
+#define MAC_CMDCFG_NO_LGTH_CHECK_GET(v)                GET_BIT_VALUE(v, 24)
+#define MAC_CMDCFG_ENA_10_GET(v)               GET_BIT_VALUE(v, 25)
+#define MAC_CMDCFG_RX_ERR_DISC_GET(v)          GET_BIT_VALUE(v, 26)
+#define MAC_CMDCFG_DISABLE_READ_TIMEOUT_GET(v) GET_BIT_VALUE(v, 27)
+#define MAC_CMDCFG_CNT_RESET_GET(v)            GET_BIT_VALUE(v, 31)
+
+/* MDIO registers within MAC register Space
+ */
+struct altera_tse_mdio {
+       u32 control;    /* PHY device operation control register */
+       u32 status;     /* PHY device operation status register */
+       u32 phy_id1;    /* Bits 31:16 of PHY identifier */
+       u32 phy_id2;    /* Bits 15:0 of PHY identifier */
+       u32 auto_negotiation_advertisement;     /* Auto-negotiation
+                                                        * advertisement
+                                                        * register
+                                                        */
+       u32 remote_partner_base_page_ability;
+
+       u32 reg6;
+       u32 reg7;
+       u32 reg8;
+       u32 reg9;
+       u32 rega;
+       u32 regb;
+       u32 regc;
+       u32 regd;
+       u32 rege;
+       u32 regf;
+       u32 reg10;
+       u32 reg11;
+       u32 reg12;
+       u32 reg13;
+       u32 reg14;
+       u32 reg15;
+       u32 reg16;
+       u32 reg17;
+       u32 reg18;
+       u32 reg19;
+       u32 reg1a;
+       u32 reg1b;
+       u32 reg1c;
+       u32 reg1d;
+       u32 reg1e;
+       u32 reg1f;
+};
+
+/* MAC register Space. Note that some of these registers may or may not be
+ * present depending upon options chosen by the user when the core was
+ * configured and built. Please consult the Altera Triple Speed Ethernet User
+ * Guide for details.
+ */
+struct altera_tse_mac {
+       /* Bits 15:0: MegaCore function revision (0x0800). Bit 31:16: Customer
+        * specific revision
+        */
+       u32 megacore_revision;
+       /* Provides a memory location for user applications to test the device
+        * memory operation.
+        */
+       u32 scratch_pad;
+       /* The host processor uses this register to control and configure the
+        * MAC block
+        */
+       u32 command_config;
+       /* 32-bit primary MAC address word 0 bits 0 to 31 of the primary
+        * MAC address
+        */
+       u32 mac_addr_0;
+       /* 32-bit primary MAC address word 1 bits 32 to 47 of the primary
+        * MAC address
+        */
+       u32 mac_addr_1;
+       /* 14-bit maximum frame length. The MAC receive logic */
+       u32 frm_length;
+       /* The pause quanta is used in each pause frame sent to a remote
+        * Ethernet device, in increments of 512 Ethernet bit times
+        */
+       u32 pause_quanta;
+       /* 12-bit receive FIFO section-empty threshold */
+       u32 rx_section_empty;
+       /* 12-bit receive FIFO section-full threshold */
+       u32 rx_section_full;
+       /* 12-bit transmit FIFO section-empty threshold */
+       u32 tx_section_empty;
+       /* 12-bit transmit FIFO section-full threshold */
+       u32 tx_section_full;
+       /* 12-bit receive FIFO almost-empty threshold */
+       u32 rx_almost_empty;
+       /* 12-bit receive FIFO almost-full threshold */
+       u32 rx_almost_full;
+       /* 12-bit transmit FIFO almost-empty threshold */
+       u32 tx_almost_empty;
+       /* 12-bit transmit FIFO almost-full threshold */
+       u32 tx_almost_full;
+       /* MDIO address of PHY Device 0. Bits 0 to 4 hold a 5-bit PHY address */
+       u32 mdio_phy0_addr;
+       /* MDIO address of PHY Device 1. Bits 0 to 4 hold a 5-bit PHY address */
+       u32 mdio_phy1_addr;
+
+       /* Bit[15:0]—16-bit holdoff quanta */
+       u32 holdoff_quant;
+
+       /* only if 100/1000 BaseX PCS, reserved otherwise */
+       u32 reserved1[5];
+
+       /* Minimum IPG between consecutive transmit frame in terms of bytes */
+       u32 tx_ipg_length;
+
+       /* IEEE 802.3 oEntity Managed Object Support */
+
+       /* The MAC addresses */
+       u32 mac_id_1;
+       u32 mac_id_2;
+
+       /* Number of frames transmitted without error including pause frames */
+       u32 frames_transmitted_ok;
+       /* Number of frames received without error including pause frames */
+       u32 frames_received_ok;
+       /* Number of frames received with a CRC error */
+       u32 frames_check_sequence_errors;
+       /* Frame received with an alignment error */
+       u32 alignment_errors;
+       /* Sum of payload and padding octets of frames transmitted without
+        * error
+        */
+       u32 octets_transmitted_ok;
+       /* Sum of payload and padding octets of frames received without error */
+       u32 octets_received_ok;
+
+       /* IEEE 802.3 oPausedEntity Managed Object Support */
+
+       /* Number of transmitted pause frames */
+       u32 tx_pause_mac_ctrl_frames;
+       /* Number of Received pause frames */
+       u32 rx_pause_mac_ctrl_frames;
+
+       /* IETF MIB (MIB-II) Object Support */
+
+       /* Number of frames received with error */
+       u32 if_in_errors;
+       /* Number of frames transmitted with error */
+       u32 if_out_errors;
+       /* Number of valid received unicast frames */
+       u32 if_in_ucast_pkts;
+       /* Number of valid received multicasts frames (without pause) */
+       u32 if_in_multicast_pkts;
+       /* Number of valid received broadcast frames */
+       u32 if_in_broadcast_pkts;
+       u32 if_out_discards;
+       /* The number of valid unicast frames transmitted */
+       u32 if_out_ucast_pkts;
+       /* The number of valid multicast frames transmitted,
+        * excluding pause frames
+        */
+       u32 if_out_multicast_pkts;
+       u32 if_out_broadcast_pkts;
+
+       /* IETF RMON MIB Object Support */
+
+       /* Counts the number of dropped packets due to internal errors
+        * of the MAC client.
+        */
+       u32 ether_stats_drop_events;
+       /* Total number of bytes received. Good and bad frames. */
+       u32 ether_stats_octets;
+       /* Total number of packets received. Counts good and bad packets. */
+       u32 ether_stats_pkts;
+       /* Number of packets received with less than 64 bytes. */
+       u32 ether_stats_undersize_pkts;
+       /* The number of frames received that are longer than the
+        * value configured in the frm_length register
+        */
+       u32 ether_stats_oversize_pkts;
+       /* Number of received packet with 64 bytes */
+       u32 ether_stats_pkts_64_octets;
+       /* Frames (good and bad) with 65 to 127 bytes */
+       u32 ether_stats_pkts_65to127_octets;
+       /* Frames (good and bad) with 128 to 255 bytes */
+       u32 ether_stats_pkts_128to255_octets;
+       /* Frames (good and bad) with 256 to 511 bytes */
+       u32 ether_stats_pkts_256to511_octets;
+       /* Frames (good and bad) with 512 to 1023 bytes */
+       u32 ether_stats_pkts_512to1023_octets;
+       /* Frames (good and bad) with 1024 to 1518 bytes */
+       u32 ether_stats_pkts_1024to1518_octets;
+
+       /* Any frame length from 1519 to the maximum length configured in the
+        * frm_length register, if it is greater than 1518
+        */
+       u32 ether_stats_pkts_1519tox_octets;
+       /* Too long frames with CRC error */
+       u32 ether_stats_jabbers;
+       /* Too short frames with CRC error */
+       u32 ether_stats_fragments;
+
+       u32 reserved2;
+
+       /* FIFO control register */
+       u32 tx_cmd_stat;
+       u32 rx_cmd_stat;
+
+       /* Extended Statistics Counters */
+       u32 msb_octets_transmitted_ok;
+       u32 msb_octets_received_ok;
+       u32 msb_ether_stats_octets;
+
+       u32 reserved3;
+
+       /* Multicast address resolution table, mapped in the controller address
+        * space
+        */
+       u32 hash_table[64];
+
+       /* Registers 0 to 31 within PHY device 0/1 connected to the MDIO PHY
+        * management interface
+        */
+       struct altera_tse_mdio mdio_phy0;
+       struct altera_tse_mdio mdio_phy1;
+
+       /* 4 Supplemental MAC Addresses */
+       u32 supp_mac_addr_0_0;
+       u32 supp_mac_addr_0_1;
+       u32 supp_mac_addr_1_0;
+       u32 supp_mac_addr_1_1;
+       u32 supp_mac_addr_2_0;
+       u32 supp_mac_addr_2_1;
+       u32 supp_mac_addr_3_0;
+       u32 supp_mac_addr_3_1;
+
+       u32 reserved4[8];
+
+       /* IEEE 1588v2 Feature */
+       u32 tx_period;
+       u32 tx_adjust_fns;
+       u32 tx_adjust_ns;
+       u32 rx_period;
+       u32 rx_adjust_fns;
+       u32 rx_adjust_ns;
+
+       u32 reserved5[42];
+};
+
+/* Transmit and Receive Command Registers Bit Definitions
+ */
+#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC                BIT(17)
+#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16      BIT(18)
+#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16      BIT(25)
+
+/* Wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct tse_buffer {
+       struct list_head lh;
+       struct sk_buff *skb;
+       dma_addr_t dma_addr;
+       u32 len;
+       int mapped_as_page;
+};
+
+struct altera_tse_private;
+
+#define ALTERA_DTYPE_SGDMA 1
+#define ALTERA_DTYPE_MSGDMA 2
+
+/* standard DMA interface for SGDMA and MSGDMA */
+struct altera_dmaops {
+       int altera_dtype;
+       int dmamask;
+       void (*reset_dma)(struct altera_tse_private *);
+       void (*enable_txirq)(struct altera_tse_private *);
+       void (*enable_rxirq)(struct altera_tse_private *);
+       void (*disable_txirq)(struct altera_tse_private *);
+       void (*disable_rxirq)(struct altera_tse_private *);
+       void (*clear_txirq)(struct altera_tse_private *);
+       void (*clear_rxirq)(struct altera_tse_private *);
+       int (*tx_buffer)(struct altera_tse_private *, struct tse_buffer *);
+       u32 (*tx_completions)(struct altera_tse_private *);
+       int (*add_rx_desc)(struct altera_tse_private *, struct tse_buffer *);
+       u32 (*get_rx_status)(struct altera_tse_private *);
+       int (*init_dma)(struct altera_tse_private *);
+       void (*uninit_dma)(struct altera_tse_private *);
+};
+
+/* This structure is private to each device.
+ */
+struct altera_tse_private {
+       struct net_device *dev;
+       struct device *device;
+       struct napi_struct napi;
+
+       /* MAC address space */
+       struct altera_tse_mac __iomem *mac_dev;
+
+       /* TSE Revision */
+       u32     revision;
+
+       /* mSGDMA Rx Dispatcher address space */
+       void __iomem *rx_dma_csr;
+       void __iomem *rx_dma_desc;
+       void __iomem *rx_dma_resp;
+
+       /* mSGDMA Tx Dispatcher address space */
+       void __iomem *tx_dma_csr;
+       void __iomem *tx_dma_desc;
+
+       /* Rx buffers queue */
+       struct tse_buffer *rx_ring;
+       u32 rx_cons;
+       u32 rx_prod;
+       u32 rx_ring_size;
+       u32 rx_dma_buf_sz;
+
+       /* Tx ring buffer */
+       struct tse_buffer *tx_ring;
+       u32 tx_prod;
+       u32 tx_cons;
+       u32 tx_ring_size;
+
+       /* Interrupts */
+       u32 tx_irq;
+       u32 rx_irq;
+
+       /* RX/TX MAC FIFO configs */
+       u32 tx_fifo_depth;
+       u32 rx_fifo_depth;
+       u32 max_mtu;
+
+       /* Hash filter settings */
+       u32 hash_filter;
+       u32 added_unicast;
+
+       /* Descriptor memory info for managing SGDMA */
+       u32 txdescmem;
+       u32 rxdescmem;
+       dma_addr_t rxdescmem_busaddr;
+       dma_addr_t txdescmem_busaddr;
+       u32 txctrlreg;
+       u32 rxctrlreg;
+       dma_addr_t rxdescphys;
+       dma_addr_t txdescphys;
+
+       struct list_head txlisthd;
+       struct list_head rxlisthd;
+
+       /* MAC command_config register protection */
+       spinlock_t mac_cfg_lock;
+       /* Tx path protection */
+       spinlock_t tx_lock;
+       /* Rx DMA & interrupt control protection */
+       spinlock_t rxdma_irq_lock;
+
+       /* PHY */
+       int phy_addr;           /* PHY's MDIO address, -1 for autodetection */
+       phy_interface_t phy_iface;
+       struct mii_bus *mdio;
+       struct phy_device *phydev;
+       int oldspeed;
+       int oldduplex;
+       int oldlink;
+
+       /* ethtool msglvl option */
+       u32 msg_enable;
+
+       struct altera_dmaops *dmaops;
+};
+
+/* Function prototypes
+ */
+void altera_tse_set_ethtool_ops(struct net_device *);
+
+#endif /* __ALTERA_TSE_H__ */
diff --git a/drivers/net/ethernet/altera/altera_tse_ethtool.c b/drivers/net/ethernet/altera/altera_tse_ethtool.c
new file mode 100644 (file)
index 0000000..63ac5f4
--- /dev/null
@@ -0,0 +1,227 @@
+/* Ethtool support for Altera Triple-Speed Ethernet MAC driver
+ * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
+ *
+ * Contributors:
+ *   Dalon Westergreen
+ *   Thomas Chou
+ *   Ian Abbott
+ *   Yuriy Kozlov
+ *   Tobias Klauser
+ *   Andriy Smolskyy
+ *   Roman Bulgakov
+ *   Dmytro Mytarchuk
+ *
+ * Original driver contributed by SLS.
+ * Major updates contributed by GlobalLogic
+ *
+ * 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/>.
+ */
+
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "altera_tse.h"
+
+#define TSE_STATS_LEN  31
+#define TSE_NUM_REGS   128
+
+static char const stat_gstrings[][ETH_GSTRING_LEN] = {
+       "tx_packets",
+       "rx_packets",
+       "rx_crc_errors",
+       "rx_align_errors",
+       "tx_bytes",
+       "rx_bytes",
+       "tx_pause",
+       "rx_pause",
+       "rx_errors",
+       "tx_errors",
+       "rx_unicast",
+       "rx_multicast",
+       "rx_broadcast",
+       "tx_discards",
+       "tx_unicast",
+       "tx_multicast",
+       "tx_broadcast",
+       "ether_drops",
+       "rx_total_bytes",
+       "rx_total_packets",
+       "rx_undersize",
+       "rx_oversize",
+       "rx_64_bytes",
+       "rx_65_127_bytes",
+       "rx_128_255_bytes",
+       "rx_256_511_bytes",
+       "rx_512_1023_bytes",
+       "rx_1024_1518_bytes",
+       "rx_gte_1519_bytes",
+       "rx_jabbers",
+       "rx_runts",
+};
+
+static void tse_get_drvinfo(struct net_device *dev,
+                           struct ethtool_drvinfo *info)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       u32 rev = ioread32(&priv->mac_dev->megacore_revision);
+
+       strcpy(info->driver, "Altera TSE MAC IP Driver");
+       strcpy(info->version, "v8.0");
+       snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d",
+                rev & 0xFFFF, (rev & 0xFFFF0000) >> 16);
+       sprintf(info->bus_info, "platform");
+}
+
+/* Fill in a buffer with the strings which correspond to the
+ * stats
+ */
+static void tse_gstrings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+       memcpy(buf, stat_gstrings, TSE_STATS_LEN * ETH_GSTRING_LEN);
+}
+
+static void tse_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+                          u64 *buf)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = priv->mac_dev;
+       u64 ext;
+
+       buf[0] = ioread32(&mac->frames_transmitted_ok);
+       buf[1] = ioread32(&mac->frames_received_ok);
+       buf[2] = ioread32(&mac->frames_check_sequence_errors);
+       buf[3] = ioread32(&mac->alignment_errors);
+
+       /* Extended aOctetsTransmittedOK counter */
+       ext = (u64) ioread32(&mac->msb_octets_transmitted_ok) << 32;
+       ext |= ioread32(&mac->octets_transmitted_ok);
+       buf[4] = ext;
+
+       /* Extended aOctetsReceivedOK counter */
+       ext = (u64) ioread32(&mac->msb_octets_received_ok) << 32;
+       ext |= ioread32(&mac->octets_received_ok);
+       buf[5] = ext;
+
+       buf[6] = ioread32(&mac->tx_pause_mac_ctrl_frames);
+       buf[7] = ioread32(&mac->rx_pause_mac_ctrl_frames);
+       buf[8] = ioread32(&mac->if_in_errors);
+       buf[9] = ioread32(&mac->if_out_errors);
+       buf[10] = ioread32(&mac->if_in_ucast_pkts);
+       buf[11] = ioread32(&mac->if_in_multicast_pkts);
+       buf[12] = ioread32(&mac->if_in_broadcast_pkts);
+       buf[13] = ioread32(&mac->if_out_discards);
+       buf[14] = ioread32(&mac->if_out_ucast_pkts);
+       buf[15] = ioread32(&mac->if_out_multicast_pkts);
+       buf[16] = ioread32(&mac->if_out_broadcast_pkts);
+       buf[17] = ioread32(&mac->ether_stats_drop_events);
+
+       /* Extended etherStatsOctets counter */
+       ext = (u64) ioread32(&mac->msb_ether_stats_octets) << 32;
+       ext |= ioread32(&mac->ether_stats_octets);
+       buf[18] = ext;
+
+       buf[19] = ioread32(&mac->ether_stats_pkts);
+       buf[20] = ioread32(&mac->ether_stats_undersize_pkts);
+       buf[21] = ioread32(&mac->ether_stats_oversize_pkts);
+       buf[22] = ioread32(&mac->ether_stats_pkts_64_octets);
+       buf[23] = ioread32(&mac->ether_stats_pkts_65to127_octets);
+       buf[24] = ioread32(&mac->ether_stats_pkts_128to255_octets);
+       buf[25] = ioread32(&mac->ether_stats_pkts_256to511_octets);
+       buf[26] = ioread32(&mac->ether_stats_pkts_512to1023_octets);
+       buf[27] = ioread32(&mac->ether_stats_pkts_1024to1518_octets);
+       buf[28] = ioread32(&mac->ether_stats_pkts_1519tox_octets);
+       buf[29] = ioread32(&mac->ether_stats_jabbers);
+       buf[30] = ioread32(&mac->ether_stats_fragments);
+}
+
+static int tse_sset_count(struct net_device *dev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return TSE_STATS_LEN;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static u32 tse_get_msglevel(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       return priv->msg_enable;
+}
+
+static void tse_set_msglevel(struct net_device *dev, uint32_t data)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       priv->msg_enable = data;
+}
+
+static int tse_reglen(struct net_device *dev)
+{
+       return TSE_NUM_REGS * sizeof(u32);
+}
+
+static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+                        void *regbuf)
+{
+       int i;
+       struct altera_tse_private *priv = netdev_priv(dev);
+       u32 *tse_mac_regs = (u32 *)priv->mac_dev;
+       u32 *buf = regbuf;
+
+       for (i = 0; i < TSE_NUM_REGS; i++)
+               buf[i] = ioread32(&tse_mac_regs[i]);
+}
+
+static int tse_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+
+       if (phydev == NULL)
+               return -ENODEV;
+
+       return phy_ethtool_gset(phydev, cmd);
+}
+
+static int tse_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+
+       if (phydev == NULL)
+               return -ENODEV;
+
+       return phy_ethtool_sset(phydev, cmd);
+}
+
+static const struct ethtool_ops tse_ethtool_ops = {
+       .get_drvinfo = tse_get_drvinfo,
+       .get_regs_len = tse_reglen,
+       .get_regs = tse_get_regs,
+       .get_link = ethtool_op_get_link,
+       .get_settings = tse_get_settings,
+       .set_settings = tse_set_settings,
+       .get_strings = tse_gstrings,
+       .get_sset_count = tse_sset_count,
+       .get_ethtool_stats = tse_fill_stats,
+       .get_msglevel = tse_get_msglevel,
+       .set_msglevel = tse_set_msglevel,
+};
+
+void altera_tse_set_ethtool_ops(struct net_device *netdev)
+{
+       SET_ETHTOOL_OPS(netdev, &tse_ethtool_ops);
+}
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
new file mode 100644 (file)
index 0000000..6006ef2
--- /dev/null
@@ -0,0 +1,1543 @@
+/* Altera Triple-Speed Ethernet MAC driver
+ * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
+ *
+ * Contributors:
+ *   Dalon Westergreen
+ *   Thomas Chou
+ *   Ian Abbott
+ *   Yuriy Kozlov
+ *   Tobias Klauser
+ *   Andriy Smolskyy
+ *   Roman Bulgakov
+ *   Dmytro Mytarchuk
+ *   Matthew Gerlach
+ *
+ * Original driver contributed by SLS.
+ * Major updates contributed by GlobalLogic
+ *
+ * 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/>.
+ */
+
+#include <linux/atomic.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/skbuff.h>
+#include <asm/cacheflush.h>
+
+#include "altera_utils.h"
+#include "altera_tse.h"
+#include "altera_sgdma.h"
+#include "altera_msgdma.h"
+
+static atomic_t instance_count = ATOMIC_INIT(~0);
+/* Module parameters */
+static int debug = -1;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)");
+
+static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+                                       NETIF_MSG_LINK | NETIF_MSG_IFUP |
+                                       NETIF_MSG_IFDOWN);
+
+#define RX_DESCRIPTORS 64
+static int dma_rx_num = RX_DESCRIPTORS;
+module_param(dma_rx_num, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dma_rx_num, "Number of descriptors in the RX list");
+
+#define TX_DESCRIPTORS 64
+static int dma_tx_num = TX_DESCRIPTORS;
+module_param(dma_tx_num, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dma_tx_num, "Number of descriptors in the TX list");
+
+
+#define POLL_PHY (-1)
+
+/* Make sure DMA buffer size is larger than the max frame size
+ * plus some alignment offset and a VLAN header. If the max frame size is
+ * 1518, a VLAN header would be additional 4 bytes and additional
+ * headroom for alignment is 2 bytes, 2048 is just fine.
+ */
+#define ALTERA_RXDMABUFFER_SIZE        2048
+
+/* Allow network stack to resume queueing packets after we've
+ * finished transmitting at least 1/4 of the packets in the queue.
+ */
+#define TSE_TX_THRESH(x)       (x->tx_ring_size / 4)
+
+#define TXQUEUESTOP_THRESHHOLD 2
+
+static struct of_device_id altera_tse_ids[];
+
+static inline u32 tse_tx_avail(struct altera_tse_private *priv)
+{
+       return priv->tx_cons + priv->tx_ring_size - priv->tx_prod - 1;
+}
+
+/* MDIO specific functions
+ */
+static int altera_tse_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       struct altera_tse_mac *mac = (struct altera_tse_mac *)bus->priv;
+       unsigned int *mdio_regs = (unsigned int *)&mac->mdio_phy0;
+       u32 data;
+
+       /* set MDIO address */
+       iowrite32((mii_id & 0x1f), &mac->mdio_phy0_addr);
+
+       /* get the data */
+       data = ioread32(&mdio_regs[regnum]) & 0xffff;
+       return data;
+}
+
+static int altera_tse_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+                                u16 value)
+{
+       struct altera_tse_mac *mac = (struct altera_tse_mac *)bus->priv;
+       unsigned int *mdio_regs = (unsigned int *)&mac->mdio_phy0;
+
+       /* set MDIO address */
+       iowrite32((mii_id & 0x1f), &mac->mdio_phy0_addr);
+
+       /* write the data */
+       iowrite32((u32) value, &mdio_regs[regnum]);
+       return 0;
+}
+
+static int altera_tse_mdio_create(struct net_device *dev, unsigned int id)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       int ret;
+       int i;
+       struct device_node *mdio_node = NULL;
+       struct mii_bus *mdio = NULL;
+       struct device_node *child_node = NULL;
+
+       for_each_child_of_node(priv->device->of_node, child_node) {
+               if (of_device_is_compatible(child_node, "altr,tse-mdio")) {
+                       mdio_node = child_node;
+                       break;
+               }
+       }
+
+       if (mdio_node) {
+               netdev_dbg(dev, "FOUND MDIO subnode\n");
+       } else {
+               netdev_dbg(dev, "NO MDIO subnode\n");
+               return 0;
+       }
+
+       mdio = mdiobus_alloc();
+       if (mdio == NULL) {
+               netdev_err(dev, "Error allocating MDIO bus\n");
+               return -ENOMEM;
+       }
+
+       mdio->name = ALTERA_TSE_RESOURCE_NAME;
+       mdio->read = &altera_tse_mdio_read;
+       mdio->write = &altera_tse_mdio_write;
+       snprintf(mdio->id, MII_BUS_ID_SIZE, "%s-%u", mdio->name, id);
+
+       mdio->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+       if (mdio->irq == NULL) {
+               ret = -ENOMEM;
+               goto out_free_mdio;
+       }
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               mdio->irq[i] = PHY_POLL;
+
+       mdio->priv = priv->mac_dev;
+       mdio->parent = priv->device;
+
+       ret = of_mdiobus_register(mdio, mdio_node);
+       if (ret != 0) {
+               netdev_err(dev, "Cannot register MDIO bus %s\n",
+                          mdio->id);
+               goto out_free_mdio_irq;
+       }
+
+       if (netif_msg_drv(priv))
+               netdev_info(dev, "MDIO bus %s: created\n", mdio->id);
+
+       priv->mdio = mdio;
+       return 0;
+out_free_mdio_irq:
+       kfree(mdio->irq);
+out_free_mdio:
+       mdiobus_free(mdio);
+       mdio = NULL;
+       return ret;
+}
+
+static void altera_tse_mdio_destroy(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+
+       if (priv->mdio == NULL)
+               return;
+
+       if (netif_msg_drv(priv))
+               netdev_info(dev, "MDIO bus %s: removed\n",
+                           priv->mdio->id);
+
+       mdiobus_unregister(priv->mdio);
+       kfree(priv->mdio->irq);
+       mdiobus_free(priv->mdio);
+       priv->mdio = NULL;
+}
+
+static int tse_init_rx_buffer(struct altera_tse_private *priv,
+                             struct tse_buffer *rxbuffer, int len)
+{
+       rxbuffer->skb = netdev_alloc_skb_ip_align(priv->dev, len);
+       if (!rxbuffer->skb)
+               return -ENOMEM;
+
+       rxbuffer->dma_addr = dma_map_single(priv->device, rxbuffer->skb->data,
+                                               len,
+                                               DMA_FROM_DEVICE);
+
+       if (dma_mapping_error(priv->device, rxbuffer->dma_addr)) {
+               netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
+               dev_kfree_skb_any(rxbuffer->skb);
+               return -EINVAL;
+       }
+       rxbuffer->len = len;
+       return 0;
+}
+
+static void tse_free_rx_buffer(struct altera_tse_private *priv,
+                              struct tse_buffer *rxbuffer)
+{
+       struct sk_buff *skb = rxbuffer->skb;
+       dma_addr_t dma_addr = rxbuffer->dma_addr;
+
+       if (skb != NULL) {
+               if (dma_addr)
+                       dma_unmap_single(priv->device, dma_addr,
+                                        rxbuffer->len,
+                                        DMA_FROM_DEVICE);
+               dev_kfree_skb_any(skb);
+               rxbuffer->skb = NULL;
+               rxbuffer->dma_addr = 0;
+       }
+}
+
+/* Unmap and free Tx buffer resources
+ */
+static void tse_free_tx_buffer(struct altera_tse_private *priv,
+                              struct tse_buffer *buffer)
+{
+       if (buffer->dma_addr) {
+               if (buffer->mapped_as_page)
+                       dma_unmap_page(priv->device, buffer->dma_addr,
+                                      buffer->len, DMA_TO_DEVICE);
+               else
+                       dma_unmap_single(priv->device, buffer->dma_addr,
+                                        buffer->len, DMA_TO_DEVICE);
+               buffer->dma_addr = 0;
+       }
+       if (buffer->skb) {
+               dev_kfree_skb_any(buffer->skb);
+               buffer->skb = NULL;
+       }
+}
+
+static int alloc_init_skbufs(struct altera_tse_private *priv)
+{
+       unsigned int rx_descs = priv->rx_ring_size;
+       unsigned int tx_descs = priv->tx_ring_size;
+       int ret = -ENOMEM;
+       int i;
+
+       /* Create Rx ring buffer */
+       priv->rx_ring = kcalloc(rx_descs, sizeof(struct tse_buffer),
+                               GFP_KERNEL);
+       if (!priv->rx_ring)
+               goto err_rx_ring;
+
+       /* Create Tx ring buffer */
+       priv->tx_ring = kcalloc(tx_descs, sizeof(struct tse_buffer),
+                               GFP_KERNEL);
+       if (!priv->tx_ring)
+               goto err_tx_ring;
+
+       priv->tx_cons = 0;
+       priv->tx_prod = 0;
+
+       /* Init Rx ring */
+       for (i = 0; i < rx_descs; i++) {
+               ret = tse_init_rx_buffer(priv, &priv->rx_ring[i],
+                                        priv->rx_dma_buf_sz);
+               if (ret)
+                       goto err_init_rx_buffers;
+       }
+
+       priv->rx_cons = 0;
+       priv->rx_prod = 0;
+
+       return 0;
+err_init_rx_buffers:
+       while (--i >= 0)
+               tse_free_rx_buffer(priv, &priv->rx_ring[i]);
+       kfree(priv->tx_ring);
+err_tx_ring:
+       kfree(priv->rx_ring);
+err_rx_ring:
+       return ret;
+}
+
+static void free_skbufs(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       unsigned int rx_descs = priv->rx_ring_size;
+       unsigned int tx_descs = priv->tx_ring_size;
+       int i;
+
+       /* Release the DMA TX/RX socket buffers */
+       for (i = 0; i < rx_descs; i++)
+               tse_free_rx_buffer(priv, &priv->rx_ring[i]);
+       for (i = 0; i < tx_descs; i++)
+               tse_free_tx_buffer(priv, &priv->tx_ring[i]);
+
+
+       kfree(priv->tx_ring);
+}
+
+/* Reallocate the skb for the reception process
+ */
+static inline void tse_rx_refill(struct altera_tse_private *priv)
+{
+       unsigned int rxsize = priv->rx_ring_size;
+       unsigned int entry;
+       int ret;
+
+       for (; priv->rx_cons - priv->rx_prod > 0;
+                       priv->rx_prod++) {
+               entry = priv->rx_prod % rxsize;
+               if (likely(priv->rx_ring[entry].skb == NULL)) {
+                       ret = tse_init_rx_buffer(priv, &priv->rx_ring[entry],
+                               priv->rx_dma_buf_sz);
+                       if (unlikely(ret != 0))
+                               break;
+                       priv->dmaops->add_rx_desc(priv, &priv->rx_ring[entry]);
+               }
+       }
+}
+
+/* Pull out the VLAN tag and fix up the packet
+ */
+static inline void tse_rx_vlan(struct net_device *dev, struct sk_buff *skb)
+{
+       struct ethhdr *eth_hdr;
+       u16 vid;
+       if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
+           !__vlan_get_tag(skb, &vid)) {
+               eth_hdr = (struct ethhdr *)skb->data;
+               memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
+               skb_pull(skb, VLAN_HLEN);
+               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
+       }
+}
+
+/* Receive a packet: retrieve and pass over to upper levels
+ */
+static int tse_rx(struct altera_tse_private *priv, int limit)
+{
+       unsigned int count = 0;
+       unsigned int next_entry;
+       struct sk_buff *skb;
+       unsigned int entry = priv->rx_cons % priv->rx_ring_size;
+       u32 rxstatus;
+       u16 pktlength;
+       u16 pktstatus;
+
+       while ((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) {
+               pktstatus = rxstatus >> 16;
+               pktlength = rxstatus & 0xffff;
+
+               if ((pktstatus & 0xFF) || (pktlength == 0))
+                       netdev_err(priv->dev,
+                                  "RCV pktstatus %08X pktlength %08X\n",
+                                  pktstatus, pktlength);
+
+               count++;
+               next_entry = (++priv->rx_cons) % priv->rx_ring_size;
+
+               skb = priv->rx_ring[entry].skb;
+               if (unlikely(!skb)) {
+                       netdev_err(priv->dev,
+                                  "%s: Inconsistent Rx descriptor chain\n",
+                                  __func__);
+                       priv->dev->stats.rx_dropped++;
+                       break;
+               }
+               priv->rx_ring[entry].skb = NULL;
+
+               skb_put(skb, pktlength);
+
+               /* make cache consistent with receive packet buffer */
+               dma_sync_single_for_cpu(priv->device,
+                                       priv->rx_ring[entry].dma_addr,
+                                       priv->rx_ring[entry].len,
+                                       DMA_FROM_DEVICE);
+
+               dma_unmap_single(priv->device, priv->rx_ring[entry].dma_addr,
+                                priv->rx_ring[entry].len, DMA_FROM_DEVICE);
+
+               if (netif_msg_pktdata(priv)) {
+                       netdev_info(priv->dev, "frame received %d bytes\n",
+                                   pktlength);
+                       print_hex_dump(KERN_ERR, "data: ", DUMP_PREFIX_OFFSET,
+                                      16, 1, skb->data, pktlength, true);
+               }
+
+               tse_rx_vlan(priv->dev, skb);
+
+               skb->protocol = eth_type_trans(skb, priv->dev);
+               skb_checksum_none_assert(skb);
+
+               napi_gro_receive(&priv->napi, skb);
+
+               priv->dev->stats.rx_packets++;
+               priv->dev->stats.rx_bytes += pktlength;
+
+               entry = next_entry;
+       }
+
+       tse_rx_refill(priv);
+       return count;
+}
+
+/* Reclaim resources after transmission completes
+ */
+static int tse_tx_complete(struct altera_tse_private *priv)
+{
+       unsigned int txsize = priv->tx_ring_size;
+       u32 ready;
+       unsigned int entry;
+       struct tse_buffer *tx_buff;
+       int txcomplete = 0;
+
+       spin_lock(&priv->tx_lock);
+
+       ready = priv->dmaops->tx_completions(priv);
+
+       /* Free sent buffers */
+       while (ready && (priv->tx_cons != priv->tx_prod)) {
+               entry = priv->tx_cons % txsize;
+               tx_buff = &priv->tx_ring[entry];
+
+               if (netif_msg_tx_done(priv))
+                       netdev_dbg(priv->dev, "%s: curr %d, dirty %d\n",
+                                  __func__, priv->tx_prod, priv->tx_cons);
+
+               if (likely(tx_buff->skb))
+                       priv->dev->stats.tx_packets++;
+
+               tse_free_tx_buffer(priv, tx_buff);
+               priv->tx_cons++;
+
+               txcomplete++;
+               ready--;
+       }
+
+       if (unlikely(netif_queue_stopped(priv->dev) &&
+                    tse_tx_avail(priv) > TSE_TX_THRESH(priv))) {
+               netif_tx_lock(priv->dev);
+               if (netif_queue_stopped(priv->dev) &&
+                   tse_tx_avail(priv) > TSE_TX_THRESH(priv)) {
+                       if (netif_msg_tx_done(priv))
+                               netdev_dbg(priv->dev, "%s: restart transmit\n",
+                                          __func__);
+                       netif_wake_queue(priv->dev);
+               }
+               netif_tx_unlock(priv->dev);
+       }
+
+       spin_unlock(&priv->tx_lock);
+       return txcomplete;
+}
+
+/* NAPI polling function
+ */
+static int tse_poll(struct napi_struct *napi, int budget)
+{
+       struct altera_tse_private *priv =
+                       container_of(napi, struct altera_tse_private, napi);
+       int rxcomplete = 0;
+       int txcomplete = 0;
+       unsigned long int flags;
+
+       txcomplete = tse_tx_complete(priv);
+
+       rxcomplete = tse_rx(priv, budget);
+
+       if (rxcomplete >= budget || txcomplete > 0)
+               return rxcomplete;
+
+       napi_gro_flush(napi, false);
+       __napi_complete(napi);
+
+       netdev_dbg(priv->dev,
+                  "NAPI Complete, did %d packets with budget %d\n",
+                  txcomplete+rxcomplete, budget);
+
+       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+       priv->dmaops->enable_rxirq(priv);
+       priv->dmaops->enable_txirq(priv);
+       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+       return rxcomplete + txcomplete;
+}
+
+/* DMA TX & RX FIFO interrupt routing
+ */
+static irqreturn_t altera_isr(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct altera_tse_private *priv;
+       unsigned long int flags;
+
+
+       if (unlikely(!dev)) {
+               pr_err("%s: invalid dev pointer\n", __func__);
+               return IRQ_NONE;
+       }
+       priv = netdev_priv(dev);
+
+       /* turn off desc irqs and enable napi rx */
+       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+
+       if (likely(napi_schedule_prep(&priv->napi))) {
+               priv->dmaops->disable_rxirq(priv);
+               priv->dmaops->disable_txirq(priv);
+               __napi_schedule(&priv->napi);
+       }
+
+       /* reset IRQs */
+       priv->dmaops->clear_rxirq(priv);
+       priv->dmaops->clear_txirq(priv);
+
+       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+/* Transmit a packet (called by the kernel). Dispatches
+ * either the SGDMA method for transmitting or the
+ * MSGDMA method, assumes no scatter/gather support,
+ * implying an assumption that there's only one
+ * physically contiguous fragment starting at
+ * skb->data, for length of skb_headlen(skb).
+ */
+static int tse_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       unsigned int txsize = priv->tx_ring_size;
+       unsigned int entry;
+       struct tse_buffer *buffer = NULL;
+       int nfrags = skb_shinfo(skb)->nr_frags;
+       unsigned int nopaged_len = skb_headlen(skb);
+       enum netdev_tx ret = NETDEV_TX_OK;
+       dma_addr_t dma_addr;
+       int txcomplete = 0;
+
+       spin_lock_bh(&priv->tx_lock);
+
+       if (unlikely(tse_tx_avail(priv) < nfrags + 1)) {
+               if (!netif_queue_stopped(dev)) {
+                       netif_stop_queue(dev);
+                       /* This is a hard error, log it. */
+                       netdev_err(priv->dev,
+                                  "%s: Tx list full when queue awake\n",
+                                  __func__);
+               }
+               ret = NETDEV_TX_BUSY;
+               goto out;
+       }
+
+       /* Map the first skb fragment */
+       entry = priv->tx_prod % txsize;
+       buffer = &priv->tx_ring[entry];
+
+       dma_addr = dma_map_single(priv->device, skb->data, nopaged_len,
+                                 DMA_TO_DEVICE);
+       if (dma_mapping_error(priv->device, dma_addr)) {
+               netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
+               ret = NETDEV_TX_OK;
+               goto out;
+       }
+
+       buffer->skb = skb;
+       buffer->dma_addr = dma_addr;
+       buffer->len = nopaged_len;
+
+       /* Push data out of the cache hierarchy into main memory */
+       dma_sync_single_for_device(priv->device, buffer->dma_addr,
+                                  buffer->len, DMA_TO_DEVICE);
+
+       txcomplete = priv->dmaops->tx_buffer(priv, buffer);
+
+       skb_tx_timestamp(skb);
+
+       priv->tx_prod++;
+       dev->stats.tx_bytes += skb->len;
+
+       if (unlikely(tse_tx_avail(priv) <= TXQUEUESTOP_THRESHHOLD)) {
+               if (netif_msg_hw(priv))
+                       netdev_dbg(priv->dev, "%s: stop transmitted packets\n",
+                                  __func__);
+               netif_stop_queue(dev);
+       }
+
+out:
+       spin_unlock_bh(&priv->tx_lock);
+
+       return ret;
+}
+
+/* Called every time the controller might need to be made
+ * aware of new link state.  The PHY code conveys this
+ * information through variables in the phydev structure, and this
+ * function converts those variables into the appropriate
+ * register values, and can bring down the device if needed.
+ */
+static void altera_tse_adjust_link(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+       int new_state = 0;
+
+       /* only change config if there is a link */
+       spin_lock(&priv->mac_cfg_lock);
+       if (phydev->link) {
+               /* Read old config */
+               u32 cfg_reg = ioread32(&priv->mac_dev->command_config);
+
+               /* Check duplex */
+               if (phydev->duplex != priv->oldduplex) {
+                       new_state = 1;
+                       if (!(phydev->duplex))
+                               cfg_reg |= MAC_CMDCFG_HD_ENA;
+                       else
+                               cfg_reg &= ~MAC_CMDCFG_HD_ENA;
+
+                       netdev_dbg(priv->dev, "%s: Link duplex = 0x%x\n",
+                                  dev->name, phydev->duplex);
+
+                       priv->oldduplex = phydev->duplex;
+               }
+
+               /* Check speed */
+               if (phydev->speed != priv->oldspeed) {
+                       new_state = 1;
+                       switch (phydev->speed) {
+                       case 1000:
+                               cfg_reg |= MAC_CMDCFG_ETH_SPEED;
+                               cfg_reg &= ~MAC_CMDCFG_ENA_10;
+                               break;
+                       case 100:
+                               cfg_reg &= ~MAC_CMDCFG_ETH_SPEED;
+                               cfg_reg &= ~MAC_CMDCFG_ENA_10;
+                               break;
+                       case 10:
+                               cfg_reg &= ~MAC_CMDCFG_ETH_SPEED;
+                               cfg_reg |= MAC_CMDCFG_ENA_10;
+                               break;
+                       default:
+                               if (netif_msg_link(priv))
+                                       netdev_warn(dev, "Speed (%d) is not 10/100/1000!\n",
+                                                   phydev->speed);
+                               break;
+                       }
+                       priv->oldspeed = phydev->speed;
+               }
+               iowrite32(cfg_reg, &priv->mac_dev->command_config);
+
+               if (!priv->oldlink) {
+                       new_state = 1;
+                       priv->oldlink = 1;
+               }
+       } else if (priv->oldlink) {
+               new_state = 1;
+               priv->oldlink = 0;
+               priv->oldspeed = 0;
+               priv->oldduplex = -1;
+       }
+
+       if (new_state && netif_msg_link(priv))
+               phy_print_status(phydev);
+
+       spin_unlock(&priv->mac_cfg_lock);
+}
+static struct phy_device *connect_local_phy(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev = NULL;
+       char phy_id_fmt[MII_BUS_ID_SIZE + 3];
+       int ret;
+
+       if (priv->phy_addr != POLL_PHY) {
+               snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
+                        priv->mdio->id, priv->phy_addr);
+
+               netdev_dbg(dev, "trying to attach to %s\n", phy_id_fmt);
+
+               phydev = phy_connect(dev, phy_id_fmt, &altera_tse_adjust_link,
+                                    priv->phy_iface);
+               if (IS_ERR(phydev))
+                       netdev_err(dev, "Could not attach to PHY\n");
+
+       } else {
+               phydev = phy_find_first(priv->mdio);
+               if (phydev == NULL) {
+                       netdev_err(dev, "No PHY found\n");
+                       return phydev;
+               }
+
+               ret = phy_connect_direct(dev, phydev, &altera_tse_adjust_link,
+                               priv->phy_iface);
+               if (ret != 0) {
+                       netdev_err(dev, "Could not attach to PHY\n");
+                       phydev = NULL;
+               }
+       }
+       return phydev;
+}
+
+/* Initialize driver's PHY state, and attach to the PHY
+ */
+static int init_phy(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev;
+       struct device_node *phynode;
+
+       priv->oldlink = 0;
+       priv->oldspeed = 0;
+       priv->oldduplex = -1;
+
+       phynode = of_parse_phandle(priv->device->of_node, "phy-handle", 0);
+
+       if (!phynode) {
+               netdev_dbg(dev, "no phy-handle found\n");
+               if (!priv->mdio) {
+                       netdev_err(dev,
+                                  "No phy-handle nor local mdio specified\n");
+                       return -ENODEV;
+               }
+               phydev = connect_local_phy(dev);
+       } else {
+               netdev_dbg(dev, "phy-handle found\n");
+               phydev = of_phy_connect(dev, phynode,
+                       &altera_tse_adjust_link, 0, priv->phy_iface);
+       }
+
+       if (!phydev) {
+               netdev_err(dev, "Could not find the PHY\n");
+               return -ENODEV;
+       }
+
+       /* Stop Advertising 1000BASE Capability if interface is not GMII
+        * Note: Checkpatch throws CHECKs for the camel case defines below,
+        * it's ok to ignore.
+        */
+       if ((priv->phy_iface == PHY_INTERFACE_MODE_MII) ||
+           (priv->phy_iface == PHY_INTERFACE_MODE_RMII))
+               phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
+                                        SUPPORTED_1000baseT_Full);
+
+       /* Broken HW is sometimes missing the pull-up resistor on the
+        * MDIO line, which results in reads to non-existent devices returning
+        * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
+        * device as well.
+        * Note: phydev->phy_id is the result of reading the UID PHY registers.
+        */
+       if (phydev->phy_id == 0) {
+               netdev_err(dev, "Bad PHY UID 0x%08x\n", phydev->phy_id);
+               phy_disconnect(phydev);
+               return -ENODEV;
+       }
+
+       netdev_dbg(dev, "attached to PHY %d UID 0x%08x Link = %d\n",
+                  phydev->addr, phydev->phy_id, phydev->link);
+
+       priv->phydev = phydev;
+       return 0;
+}
+
+static void tse_update_mac_addr(struct altera_tse_private *priv, u8 *addr)
+{
+       struct altera_tse_mac *mac = priv->mac_dev;
+       u32 msb;
+       u32 lsb;
+
+       msb = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+       lsb = ((addr[5] << 8) | addr[4]) & 0xffff;
+
+       /* Set primary MAC address */
+       iowrite32(msb, &mac->mac_addr_0);
+       iowrite32(lsb, &mac->mac_addr_1);
+}
+
+/* MAC software reset.
+ * When reset is triggered, the MAC function completes the current
+ * transmission or reception, and subsequently disables the transmit and
+ * receive logic, flushes the receive FIFO buffer, and resets the statistics
+ * counters.
+ */
+static int reset_mac(struct altera_tse_private *priv)
+{
+       void __iomem *cmd_cfg_reg = &priv->mac_dev->command_config;
+       int counter;
+       u32 dat;
+
+       dat = ioread32(cmd_cfg_reg);
+       dat &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA);
+       dat |= MAC_CMDCFG_SW_RESET | MAC_CMDCFG_CNT_RESET;
+       iowrite32(dat, cmd_cfg_reg);
+
+       counter = 0;
+       while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+               if (tse_bit_is_clear(cmd_cfg_reg, MAC_CMDCFG_SW_RESET))
+                       break;
+               udelay(1);
+       }
+
+       if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+               dat = ioread32(cmd_cfg_reg);
+               dat &= ~MAC_CMDCFG_SW_RESET;
+               iowrite32(dat, cmd_cfg_reg);
+               return -1;
+       }
+       return 0;
+}
+
+/* Initialize MAC core registers
+*/
+static int init_mac(struct altera_tse_private *priv)
+{
+       struct altera_tse_mac *mac = priv->mac_dev;
+       unsigned int cmd = 0;
+       u32 frm_length;
+
+       /* Setup Rx FIFO */
+       iowrite32(priv->rx_fifo_depth - ALTERA_TSE_RX_SECTION_EMPTY,
+                 &mac->rx_section_empty);
+       iowrite32(ALTERA_TSE_RX_SECTION_FULL, &mac->rx_section_full);
+       iowrite32(ALTERA_TSE_RX_ALMOST_EMPTY, &mac->rx_almost_empty);
+       iowrite32(ALTERA_TSE_RX_ALMOST_FULL, &mac->rx_almost_full);
+
+       /* Setup Tx FIFO */
+       iowrite32(priv->tx_fifo_depth - ALTERA_TSE_TX_SECTION_EMPTY,
+                 &mac->tx_section_empty);
+       iowrite32(ALTERA_TSE_TX_SECTION_FULL, &mac->tx_section_full);
+       iowrite32(ALTERA_TSE_TX_ALMOST_EMPTY, &mac->tx_almost_empty);
+       iowrite32(ALTERA_TSE_TX_ALMOST_FULL, &mac->tx_almost_full);
+
+       /* MAC Address Configuration */
+       tse_update_mac_addr(priv, priv->dev->dev_addr);
+
+       /* MAC Function Configuration */
+       frm_length = ETH_HLEN + priv->dev->mtu + ETH_FCS_LEN;
+       iowrite32(frm_length, &mac->frm_length);
+       iowrite32(ALTERA_TSE_TX_IPG_LENGTH, &mac->tx_ipg_length);
+
+       /* Disable RX/TX shift 16 for alignment of all received frames on 16-bit
+        * start address
+        */
+       tse_clear_bit(&mac->rx_cmd_stat, ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16);
+       tse_clear_bit(&mac->tx_cmd_stat, ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 |
+                                        ALTERA_TSE_TX_CMD_STAT_OMIT_CRC);
+
+       /* Set the MAC options */
+       cmd = ioread32(&mac->command_config);
+       cmd |= MAC_CMDCFG_PAD_EN;       /* Padding Removal on Receive */
+       cmd &= ~MAC_CMDCFG_CRC_FWD;     /* CRC Removal */
+       cmd |= MAC_CMDCFG_RX_ERR_DISC;  /* Automatically discard frames
+                                        * with CRC errors
+                                        */
+       cmd |= MAC_CMDCFG_CNTL_FRM_ENA;
+       cmd &= ~MAC_CMDCFG_TX_ENA;
+       cmd &= ~MAC_CMDCFG_RX_ENA;
+       iowrite32(cmd, &mac->command_config);
+
+       if (netif_msg_hw(priv))
+               dev_dbg(priv->device,
+                       "MAC post-initialization: CMD_CONFIG = 0x%08x\n", cmd);
+
+       return 0;
+}
+
+/* Start/stop MAC transmission logic
+ */
+static void tse_set_mac(struct altera_tse_private *priv, bool enable)
+{
+       struct altera_tse_mac *mac = priv->mac_dev;
+       u32 value = ioread32(&mac->command_config);
+
+       if (enable)
+               value |= MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA;
+       else
+               value &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA);
+
+       iowrite32(value, &mac->command_config);
+}
+
+/* Change the MTU
+ */
+static int tse_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       unsigned int max_mtu = priv->max_mtu;
+       unsigned int min_mtu = ETH_ZLEN + ETH_FCS_LEN;
+
+       if (netif_running(dev)) {
+               netdev_err(dev, "must be stopped to change its MTU\n");
+               return -EBUSY;
+       }
+
+       if ((new_mtu < min_mtu) || (new_mtu > max_mtu)) {
+               netdev_err(dev, "invalid MTU, max MTU is: %u\n", max_mtu);
+               return -EINVAL;
+       }
+
+       dev->mtu = new_mtu;
+       netdev_update_features(dev);
+
+       return 0;
+}
+
+static void altera_tse_set_mcfilter(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = (struct altera_tse_mac *)priv->mac_dev;
+       int i;
+       struct netdev_hw_addr *ha;
+
+       /* clear the hash filter */
+       for (i = 0; i < 64; i++)
+               iowrite32(0, &(mac->hash_table[i]));
+
+       netdev_for_each_mc_addr(ha, dev) {
+               unsigned int hash = 0;
+               int mac_octet;
+
+               for (mac_octet = 5; mac_octet >= 0; mac_octet--) {
+                       unsigned char xor_bit = 0;
+                       unsigned char octet = ha->addr[mac_octet];
+                       unsigned int bitshift;
+
+                       for (bitshift = 0; bitshift < 8; bitshift++)
+                               xor_bit ^= ((octet >> bitshift) & 0x01);
+
+                       hash = (hash << 1) | xor_bit;
+               }
+               iowrite32(1, &(mac->hash_table[hash]));
+       }
+}
+
+
+static void altera_tse_set_mcfilterall(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = (struct altera_tse_mac *)priv->mac_dev;
+       int i;
+
+       /* set the hash filter */
+       for (i = 0; i < 64; i++)
+               iowrite32(1, &(mac->hash_table[i]));
+}
+
+/* Set or clear the multicast filter for this adaptor
+ */
+static void tse_set_rx_mode_hashfilter(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = priv->mac_dev;
+
+       spin_lock(&priv->mac_cfg_lock);
+
+       if (dev->flags & IFF_PROMISC)
+               tse_set_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN);
+
+       if (dev->flags & IFF_ALLMULTI)
+               altera_tse_set_mcfilterall(dev);
+       else
+               altera_tse_set_mcfilter(dev);
+
+       spin_unlock(&priv->mac_cfg_lock);
+}
+
+/* Set or clear the multicast filter for this adaptor
+ */
+static void tse_set_rx_mode(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = priv->mac_dev;
+
+       spin_lock(&priv->mac_cfg_lock);
+
+       if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
+           !netdev_mc_empty(dev) || !netdev_uc_empty(dev))
+               tse_set_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN);
+       else
+               tse_clear_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN);
+
+       spin_unlock(&priv->mac_cfg_lock);
+}
+
+/* Open and initialize the interface
+ */
+static int tse_open(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       int ret = 0;
+       int i;
+       unsigned long int flags;
+
+       /* Reset and configure TSE MAC and probe associated PHY */
+       ret = priv->dmaops->init_dma(priv);
+       if (ret != 0) {
+               netdev_err(dev, "Cannot initialize DMA\n");
+               goto phy_error;
+       }
+
+       if (netif_msg_ifup(priv))
+               netdev_warn(dev, "device MAC address %pM\n",
+                           dev->dev_addr);
+
+       if ((priv->revision < 0xd00) || (priv->revision > 0xe00))
+               netdev_warn(dev, "TSE revision %x\n", priv->revision);
+
+       spin_lock(&priv->mac_cfg_lock);
+       ret = reset_mac(priv);
+       if (ret)
+               netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret);
+
+       ret = init_mac(priv);
+       spin_unlock(&priv->mac_cfg_lock);
+       if (ret) {
+               netdev_err(dev, "Cannot init MAC core (error: %d)\n", ret);
+               goto alloc_skbuf_error;
+       }
+
+       priv->dmaops->reset_dma(priv);
+
+       /* Create and initialize the TX/RX descriptors chains. */
+       priv->rx_ring_size = dma_rx_num;
+       priv->tx_ring_size = dma_tx_num;
+       ret = alloc_init_skbufs(priv);
+       if (ret) {
+               netdev_err(dev, "DMA descriptors initialization failed\n");
+               goto alloc_skbuf_error;
+       }
+
+
+       /* Register RX interrupt */
+       ret = request_irq(priv->rx_irq, altera_isr, IRQF_SHARED,
+                         dev->name, dev);
+       if (ret) {
+               netdev_err(dev, "Unable to register RX interrupt %d\n",
+                          priv->rx_irq);
+               goto init_error;
+       }
+
+       /* Register TX interrupt */
+       ret = request_irq(priv->tx_irq, altera_isr, IRQF_SHARED,
+                         dev->name, dev);
+       if (ret) {
+               netdev_err(dev, "Unable to register TX interrupt %d\n",
+                          priv->tx_irq);
+               goto tx_request_irq_error;
+       }
+
+       /* Enable DMA interrupts */
+       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+       priv->dmaops->enable_rxirq(priv);
+       priv->dmaops->enable_txirq(priv);
+
+       /* Setup RX descriptor chain */
+       for (i = 0; i < priv->rx_ring_size; i++)
+               priv->dmaops->add_rx_desc(priv, &priv->rx_ring[i]);
+
+       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+
+       /* Start MAC Rx/Tx */
+       spin_lock(&priv->mac_cfg_lock);
+       tse_set_mac(priv, true);
+       spin_unlock(&priv->mac_cfg_lock);
+
+       if (priv->phydev)
+               phy_start(priv->phydev);
+
+       napi_enable(&priv->napi);
+       netif_start_queue(dev);
+
+       return 0;
+
+tx_request_irq_error:
+       free_irq(priv->rx_irq, dev);
+init_error:
+       free_skbufs(dev);
+alloc_skbuf_error:
+       if (priv->phydev) {
+               phy_disconnect(priv->phydev);
+               priv->phydev = NULL;
+       }
+phy_error:
+       return ret;
+}
+
+/* Stop TSE MAC interface and put the device in an inactive state
+ */
+static int tse_shutdown(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       int ret;
+       unsigned long int flags;
+
+       /* Stop and disconnect the PHY */
+       if (priv->phydev) {
+               phy_stop(priv->phydev);
+               phy_disconnect(priv->phydev);
+               priv->phydev = NULL;
+       }
+
+       netif_stop_queue(dev);
+       napi_disable(&priv->napi);
+
+       /* Disable DMA interrupts */
+       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+       priv->dmaops->disable_rxirq(priv);
+       priv->dmaops->disable_txirq(priv);
+       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+
+       /* Free the IRQ lines */
+       free_irq(priv->rx_irq, dev);
+       free_irq(priv->tx_irq, dev);
+
+       /* disable and reset the MAC, empties fifo */
+       spin_lock(&priv->mac_cfg_lock);
+       spin_lock(&priv->tx_lock);
+
+       ret = reset_mac(priv);
+       if (ret)
+               netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret);
+       priv->dmaops->reset_dma(priv);
+       free_skbufs(dev);
+
+       spin_unlock(&priv->tx_lock);
+       spin_unlock(&priv->mac_cfg_lock);
+
+       priv->dmaops->uninit_dma(priv);
+
+       return 0;
+}
+
+static struct net_device_ops altera_tse_netdev_ops = {
+       .ndo_open               = tse_open,
+       .ndo_stop               = tse_shutdown,
+       .ndo_start_xmit         = tse_start_xmit,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_rx_mode        = tse_set_rx_mode,
+       .ndo_change_mtu         = tse_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+
+static int request_and_map(struct platform_device *pdev, const char *name,
+                          struct resource **res, void __iomem **ptr)
+{
+       struct resource *region;
+       struct device *device = &pdev->dev;
+
+       *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       if (*res == NULL) {
+               dev_err(device, "resource %s not defined\n", name);
+               return -ENODEV;
+       }
+
+       region = devm_request_mem_region(device, (*res)->start,
+                                        resource_size(*res), dev_name(device));
+       if (region == NULL) {
+               dev_err(device, "unable to request %s\n", name);
+               return -EBUSY;
+       }
+
+       *ptr = devm_ioremap_nocache(device, region->start,
+                                   resource_size(region));
+       if (*ptr == NULL) {
+               dev_err(device, "ioremap_nocache of %s failed!", name);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/* Probe Altera TSE MAC device
+ */
+static int altera_tse_probe(struct platform_device *pdev)
+{
+       struct net_device *ndev;
+       int ret = -ENODEV;
+       struct resource *control_port;
+       struct resource *dma_res;
+       struct altera_tse_private *priv;
+       const unsigned char *macaddr;
+       struct device_node *np = pdev->dev.of_node;
+       void __iomem *descmap;
+       const struct of_device_id *of_id = NULL;
+
+       ndev = alloc_etherdev(sizeof(struct altera_tse_private));
+       if (!ndev) {
+               dev_err(&pdev->dev, "Could not allocate network device\n");
+               return -ENODEV;
+       }
+
+       SET_NETDEV_DEV(ndev, &pdev->dev);
+
+       priv = netdev_priv(ndev);
+       priv->device = &pdev->dev;
+       priv->dev = ndev;
+       priv->msg_enable = netif_msg_init(debug, default_msg_level);
+
+       of_id = of_match_device(altera_tse_ids, &pdev->dev);
+
+       if (of_id)
+               priv->dmaops = (struct altera_dmaops *)of_id->data;
+
+
+       if (priv->dmaops &&
+           priv->dmaops->altera_dtype == ALTERA_DTYPE_SGDMA) {
+               /* Get the mapped address to the SGDMA descriptor memory */
+               ret = request_and_map(pdev, "s1", &dma_res, &descmap);
+               if (ret)
+                       goto out_free;
+
+               /* Start of that memory is for transmit descriptors */
+               priv->tx_dma_desc = descmap;
+
+               /* First half is for tx descriptors, other half for tx */
+               priv->txdescmem = resource_size(dma_res)/2;
+
+               priv->txdescmem_busaddr = (dma_addr_t)dma_res->start;
+
+               priv->rx_dma_desc = (void __iomem *)((uintptr_t)(descmap +
+                                                    priv->txdescmem));
+               priv->rxdescmem = resource_size(dma_res)/2;
+               priv->rxdescmem_busaddr = dma_res->start;
+               priv->rxdescmem_busaddr += priv->txdescmem;
+
+               if (upper_32_bits(priv->rxdescmem_busaddr)) {
+                       dev_dbg(priv->device,
+                               "SGDMA bus addresses greater than 32-bits\n");
+                       goto out_free;
+               }
+               if (upper_32_bits(priv->txdescmem_busaddr)) {
+                       dev_dbg(priv->device,
+                               "SGDMA bus addresses greater than 32-bits\n");
+                       goto out_free;
+               }
+       } else if (priv->dmaops &&
+                  priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) {
+               ret = request_and_map(pdev, "rx_resp", &dma_res,
+                                     &priv->rx_dma_resp);
+               if (ret)
+                       goto out_free;
+
+               ret = request_and_map(pdev, "tx_desc", &dma_res,
+                                     &priv->tx_dma_desc);
+               if (ret)
+                       goto out_free;
+
+               priv->txdescmem = resource_size(dma_res);
+               priv->txdescmem_busaddr = dma_res->start;
+
+               ret = request_and_map(pdev, "rx_desc", &dma_res,
+                                     &priv->rx_dma_desc);
+               if (ret)
+                       goto out_free;
+
+               priv->rxdescmem = resource_size(dma_res);
+               priv->rxdescmem_busaddr = dma_res->start;
+
+       } else {
+               goto out_free;
+       }
+
+       if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask)))
+               dma_set_coherent_mask(priv->device,
+                                     DMA_BIT_MASK(priv->dmaops->dmamask));
+       else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32)))
+               dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32));
+       else
+               goto out_free;
+
+       /* MAC address space */
+       ret = request_and_map(pdev, "control_port", &control_port,
+                             (void __iomem **)&priv->mac_dev);
+       if (ret)
+               goto out_free;
+
+       /* xSGDMA Rx Dispatcher address space */
+       ret = request_and_map(pdev, "rx_csr", &dma_res,
+                             &priv->rx_dma_csr);
+       if (ret)
+               goto out_free;
+
+
+       /* xSGDMA Tx Dispatcher address space */
+       ret = request_and_map(pdev, "tx_csr", &dma_res,
+                             &priv->tx_dma_csr);
+       if (ret)
+               goto out_free;
+
+
+       /* Rx IRQ */
+       priv->rx_irq = platform_get_irq_byname(pdev, "rx_irq");
+       if (priv->rx_irq == -ENXIO) {
+               dev_err(&pdev->dev, "cannot obtain Rx IRQ\n");
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       /* Tx IRQ */
+       priv->tx_irq = platform_get_irq_byname(pdev, "tx_irq");
+       if (priv->tx_irq == -ENXIO) {
+               dev_err(&pdev->dev, "cannot obtain Tx IRQ\n");
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       /* get FIFO depths from device tree */
+       if (of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth",
+                                &priv->rx_fifo_depth)) {
+               dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n");
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
+                                &priv->rx_fifo_depth)) {
+               dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n");
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       /* get hash filter settings for this instance */
+       priv->hash_filter =
+               of_property_read_bool(pdev->dev.of_node,
+                                     "altr,has-hash-multicast-filter");
+
+       /* get supplemental address settings for this instance */
+       priv->added_unicast =
+               of_property_read_bool(pdev->dev.of_node,
+                                     "altr,has-supplementary-unicast");
+
+       /* Max MTU is 1500, ETH_DATA_LEN */
+       priv->max_mtu = ETH_DATA_LEN;
+
+       /* Get the max mtu from the device tree. Note that the
+        * "max-frame-size" parameter is actually max mtu. Definition
+        * in the ePAPR v1.1 spec and usage differ, so go with usage.
+        */
+       of_property_read_u32(pdev->dev.of_node, "max-frame-size",
+                            &priv->max_mtu);
+
+       /* The DMA buffer size already accounts for an alignment bias
+        * to avoid unaligned access exceptions for the NIOS processor,
+        */
+       priv->rx_dma_buf_sz = ALTERA_RXDMABUFFER_SIZE;
+
+       /* get default MAC address from device tree */
+       macaddr = of_get_mac_address(pdev->dev.of_node);
+       if (macaddr)
+               ether_addr_copy(ndev->dev_addr, macaddr);
+       else
+               eth_hw_addr_random(ndev);
+
+       priv->phy_iface = of_get_phy_mode(np);
+
+       /* try to get PHY address from device tree, use PHY autodetection if
+        * no valid address is given
+        */
+       if (of_property_read_u32(pdev->dev.of_node, "phy-addr",
+                                &priv->phy_addr)) {
+               priv->phy_addr = POLL_PHY;
+       }
+
+       if (!((priv->phy_addr == POLL_PHY) ||
+             ((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) {
+               dev_err(&pdev->dev, "invalid phy-addr specified %d\n",
+                       priv->phy_addr);
+               goto out_free;
+       }
+
+       /* Create/attach to MDIO bus */
+       ret = altera_tse_mdio_create(ndev,
+                                    atomic_add_return(1, &instance_count));
+
+       if (ret)
+               goto out_free;
+
+       /* initialize netdev */
+       ether_setup(ndev);
+       ndev->mem_start = control_port->start;
+       ndev->mem_end = control_port->end;
+       ndev->netdev_ops = &altera_tse_netdev_ops;
+       altera_tse_set_ethtool_ops(ndev);
+
+       altera_tse_netdev_ops.ndo_set_rx_mode = tse_set_rx_mode;
+
+       if (priv->hash_filter)
+               altera_tse_netdev_ops.ndo_set_rx_mode =
+                       tse_set_rx_mode_hashfilter;
+
+       /* Scatter/gather IO is not supported,
+        * so it is turned off
+        */
+       ndev->hw_features &= ~NETIF_F_SG;
+       ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;
+
+       /* VLAN offloading of tagging, stripping and filtering is not
+        * supported by hardware, but driver will accommodate the
+        * extra 4-byte VLAN tag for processing by upper layers
+        */
+       ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+
+       /* setup NAPI interface */
+       netif_napi_add(ndev, &priv->napi, tse_poll, NAPI_POLL_WEIGHT);
+
+       spin_lock_init(&priv->mac_cfg_lock);
+       spin_lock_init(&priv->tx_lock);
+       spin_lock_init(&priv->rxdma_irq_lock);
+
+       ret = register_netdev(ndev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register TSE net device\n");
+               goto out_free_mdio;
+       }
+
+       platform_set_drvdata(pdev, ndev);
+
+       priv->revision = ioread32(&priv->mac_dev->megacore_revision);
+
+       if (netif_msg_probe(priv))
+               dev_info(&pdev->dev, "Altera TSE MAC version %d.%d at 0x%08lx irq %d/%d\n",
+                        (priv->revision >> 8) & 0xff,
+                        priv->revision & 0xff,
+                        (unsigned long) control_port->start, priv->rx_irq,
+                        priv->tx_irq);
+
+       ret = init_phy(ndev);
+       if (ret != 0) {
+               netdev_err(ndev, "Cannot attach to PHY (error: %d)\n", ret);
+               goto out_free_mdio;
+       }
+       return 0;
+
+out_free_mdio:
+       altera_tse_mdio_destroy(ndev);
+out_free:
+       free_netdev(ndev);
+       return ret;
+}
+
+/* Remove Altera TSE MAC device
+ */
+static int altera_tse_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       altera_tse_mdio_destroy(ndev);
+       unregister_netdev(ndev);
+       free_netdev(ndev);
+
+       return 0;
+}
+
+struct altera_dmaops altera_dtype_sgdma = {
+       .altera_dtype = ALTERA_DTYPE_SGDMA,
+       .dmamask = 32,
+       .reset_dma = sgdma_reset,
+       .enable_txirq = sgdma_enable_txirq,
+       .enable_rxirq = sgdma_enable_rxirq,
+       .disable_txirq = sgdma_disable_txirq,
+       .disable_rxirq = sgdma_disable_rxirq,
+       .clear_txirq = sgdma_clear_txirq,
+       .clear_rxirq = sgdma_clear_rxirq,
+       .tx_buffer = sgdma_tx_buffer,
+       .tx_completions = sgdma_tx_completions,
+       .add_rx_desc = sgdma_add_rx_desc,
+       .get_rx_status = sgdma_rx_status,
+       .init_dma = sgdma_initialize,
+       .uninit_dma = sgdma_uninitialize,
+};
+
+struct altera_dmaops altera_dtype_msgdma = {
+       .altera_dtype = ALTERA_DTYPE_MSGDMA,
+       .dmamask = 64,
+       .reset_dma = msgdma_reset,
+       .enable_txirq = msgdma_enable_txirq,
+       .enable_rxirq = msgdma_enable_rxirq,
+       .disable_txirq = msgdma_disable_txirq,
+       .disable_rxirq = msgdma_disable_rxirq,
+       .clear_txirq = msgdma_clear_txirq,
+       .clear_rxirq = msgdma_clear_rxirq,
+       .tx_buffer = msgdma_tx_buffer,
+       .tx_completions = msgdma_tx_completions,
+       .add_rx_desc = msgdma_add_rx_desc,
+       .get_rx_status = msgdma_rx_status,
+       .init_dma = msgdma_initialize,
+       .uninit_dma = msgdma_uninitialize,
+};
+
+static struct of_device_id altera_tse_ids[] = {
+       { .compatible = "altr,tse-msgdma-1.0", .data = &altera_dtype_msgdma, },
+       { .compatible = "altr,tse-1.0", .data = &altera_dtype_sgdma, },
+       { .compatible = "ALTR,tse-1.0", .data = &altera_dtype_sgdma, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, altera_tse_ids);
+
+static struct platform_driver altera_tse_driver = {
+       .probe          = altera_tse_probe,
+       .remove         = altera_tse_remove,
+       .suspend        = NULL,
+       .resume         = NULL,
+       .driver         = {
+               .name   = ALTERA_TSE_RESOURCE_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = altera_tse_ids,
+       },
+};
+
+module_platform_driver(altera_tse_driver);
+
+MODULE_AUTHOR("Altera Corporation");
+MODULE_DESCRIPTION("Altera Triple Speed Ethernet MAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/altera/altera_utils.c b/drivers/net/ethernet/altera/altera_utils.c
new file mode 100644 (file)
index 0000000..70fa13f
--- /dev/null
@@ -0,0 +1,44 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * 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/>.
+ */
+
+#include "altera_tse.h"
+#include "altera_utils.h"
+
+void tse_set_bit(void __iomem *ioaddr, u32 bit_mask)
+{
+       u32 value = ioread32(ioaddr);
+       value |= bit_mask;
+       iowrite32(value, ioaddr);
+}
+
+void tse_clear_bit(void __iomem *ioaddr, u32 bit_mask)
+{
+       u32 value = ioread32(ioaddr);
+       value &= ~bit_mask;
+       iowrite32(value, ioaddr);
+}
+
+int tse_bit_is_set(void __iomem *ioaddr, u32 bit_mask)
+{
+       u32 value = ioread32(ioaddr);
+       return (value & bit_mask) ? 1 : 0;
+}
+
+int tse_bit_is_clear(void __iomem *ioaddr, u32 bit_mask)
+{
+       u32 value = ioread32(ioaddr);
+       return (value & bit_mask) ? 0 : 1;
+}
diff --git a/drivers/net/ethernet/altera/altera_utils.h b/drivers/net/ethernet/altera/altera_utils.h
new file mode 100644 (file)
index 0000000..ce1db36
--- /dev/null
@@ -0,0 +1,27 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * 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/>.
+ */
+
+#include <linux/kernel.h>
+
+#ifndef __ALTERA_UTILS_H__
+#define __ALTERA_UTILS_H__
+
+void tse_set_bit(void __iomem *ioaddr, u32 bit_mask);
+void tse_clear_bit(void __iomem *ioaddr, u32 bit_mask);
+int tse_bit_is_set(void __iomem *ioaddr, u32 bit_mask);
+int tse_bit_is_clear(void __iomem *ioaddr, u32 bit_mask);
+
+#endif /* __ALTERA_UTILS_H__*/
index 2061b471fd161b92cd9c4161fa15b955b63a28e2..26efaaa5e73fd292de512fc428e9af84126fcbb9 100644 (file)
@@ -720,6 +720,9 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget)
        int rx_pkt_limit = budget;
        unsigned long flags;
 
+       if (rx_pkt_limit <= 0)
+               goto rx_not_empty;
+
        do{
                /* process receive packets until we use the quota*/
                /* If we own the next entry, it's a new packet. Send it up. */
index 1f7b5aa114fae3ee3adf589af58e5def31fc84d7..05ba6258901794ab51842ddc8d630f4d1286798d 100644 (file)
@@ -1484,6 +1484,10 @@ static int b44_open(struct net_device *dev)
        add_timer(&bp->timer);
 
        b44_enable_ints(bp);
+
+       if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+               phy_start(bp->phydev);
+
        netif_start_queue(dev);
 out:
        return err;
@@ -1646,6 +1650,9 @@ static int b44_close(struct net_device *dev)
 
        netif_stop_queue(dev);
 
+       if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+               phy_stop(bp->phydev);
+
        napi_disable(&bp->napi);
 
        del_timer_sync(&bp->timer);
@@ -1678,7 +1685,7 @@ static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev,
        unsigned int start;
 
        do {
-               start = u64_stats_fetch_begin_bh(&hwstat->syncp);
+               start = u64_stats_fetch_begin_irq(&hwstat->syncp);
 
                /* Convert HW stats into rtnl_link_stats64 stats. */
                nstat->rx_packets = hwstat->rx_pkts;
@@ -1712,7 +1719,7 @@ static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev,
                /* Carrier lost counter seems to be broken for some devices */
                nstat->tx_carrier_errors = hwstat->tx_carrier_lost;
 #endif
-       } while (u64_stats_fetch_retry_bh(&hwstat->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start));
 
        return nstat;
 }
@@ -2066,12 +2073,12 @@ static void b44_get_ethtool_stats(struct net_device *dev,
        do {
                data_src = &hwstat->tx_good_octets;
                data_dst = data;
-               start = u64_stats_fetch_begin_bh(&hwstat->syncp);
+               start = u64_stats_fetch_begin_irq(&hwstat->syncp);
 
                for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++)
                        *data_dst++ = *data_src++;
 
-       } while (u64_stats_fetch_retry_bh(&hwstat->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start));
 }
 
 static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -2222,7 +2229,12 @@ static void b44_adjust_link(struct net_device *dev)
        }
 
        if (status_changed) {
-               b44_check_phy(bp);
+               u32 val = br32(bp, B44_TX_CTRL);
+               if (bp->flags & B44_FLAG_FULL_DUPLEX)
+                       val |= TX_CTRL_DUPLEX;
+               else
+                       val &= ~TX_CTRL_DUPLEX;
+               bw32(bp, B44_TX_CTRL, val);
                phy_print_status(phydev);
        }
 }
index b9a5fb6400d3cf1917511dec27c92486a46f12fc..a7d11f5565d69342ad296471a9a5d44f8d7c51d5 100644 (file)
@@ -1722,9 +1722,6 @@ static const struct net_device_ops bcm_enet_ops = {
        .ndo_set_rx_mode        = bcm_enet_set_multicast_list,
        .ndo_do_ioctl           = bcm_enet_ioctl,
        .ndo_change_mtu         = bcm_enet_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller = bcm_enet_netpoll,
-#endif
 };
 
 /*
index ca6b36220d9440d58dda2de90adce6cc2f49a9ed..a8efb18e42fa66a01fd1950977db55b96ab15022 100644 (file)
@@ -2507,6 +2507,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
 
        bp->fw_wr_seq++;
        msg_data |= bp->fw_wr_seq;
+       bp->fw_last_msg = msg_data;
 
        bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
 
@@ -2885,7 +2886,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                sw_cons = BNX2_NEXT_TX_BD(sw_cons);
 
                tx_bytes += skb->len;
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                tx_pkt++;
                if (tx_pkt == budget)
                        break;
@@ -3132,6 +3133,9 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
        struct l2_fhdr *rx_hdr;
        int rx_pkt = 0, pg_ring_used = 0;
 
+       if (budget <= 0)
+               return rx_pkt;
+
        hw_cons = bnx2_get_hw_rx_cons(bnapi);
        sw_cons = rxr->rx_cons;
        sw_prod = rxr->rx_prod;
@@ -4000,8 +4004,23 @@ bnx2_setup_wol(struct bnx2 *bp)
                        wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
        }
 
-       if (!(bp->flags & BNX2_FLAG_NO_WOL))
-               bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 1, 0);
+       if (!(bp->flags & BNX2_FLAG_NO_WOL)) {
+               u32 val;
+
+               wol_msg |= BNX2_DRV_MSG_DATA_WAIT3;
+               if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) {
+                       bnx2_fw_sync(bp, wol_msg, 1, 0);
+                       return;
+               }
+               /* Tell firmware not to power down the PHY yet, otherwise
+                * the chip will take a long time to respond to MMIO reads.
+                */
+               val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
+               bnx2_shmem_wr(bp, BNX2_PORT_FEATURE,
+                             val | BNX2_PORT_FEATURE_ASF_ENABLED);
+               bnx2_fw_sync(bp, wol_msg, 1, 0);
+               bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val);
+       }
 
 }
 
@@ -4033,9 +4052,22 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
 
                        if (bp->wol)
                                pci_set_power_state(bp->pdev, PCI_D3hot);
-               } else {
-                       pci_set_power_state(bp->pdev, PCI_D3hot);
+                       break;
+
+               }
+               if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) {
+                       u32 val;
+
+                       /* Tell firmware not to power down the PHY yet,
+                        * otherwise the other port may not respond to
+                        * MMIO reads.
+                        */
+                       val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
+                       val &= ~BNX2_CONDITION_PM_STATE_MASK;
+                       val |= BNX2_CONDITION_PM_STATE_UNPREP;
+                       bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);
                }
+               pci_set_power_state(bp->pdev, PCI_D3hot);
 
                /* No more memory access after this point until
                 * device is brought back to D0.
@@ -6604,7 +6636,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
        if (dma_mapping_error(&bp->pdev->dev, mapping)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -6697,7 +6729,7 @@ dma_error:
                               PCI_DMA_TODEVICE);
        }
 
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
index f1cf2c44e7ed549519fe2eaf860d0d01302b032d..e341bc366fa5f1d003a9355516a8ebdd81811ac8 100644 (file)
@@ -6900,6 +6900,7 @@ struct bnx2 {
 
        u16                     fw_wr_seq;
        u16                     fw_drv_pulse_wr_seq;
+       u32                     fw_last_msg;
 
        int                     rx_max_ring;
        int                     rx_ring_size;
@@ -7406,6 +7407,10 @@ struct bnx2_rv2p_fw_file {
 #define BNX2_CONDITION_MFW_RUN_NCSI             0x00006000
 #define BNX2_CONDITION_MFW_RUN_NONE             0x0000e000
 #define BNX2_CONDITION_MFW_RUN_MASK             0x0000e000
+#define BNX2_CONDITION_PM_STATE_MASK            0x00030000
+#define BNX2_CONDITION_PM_STATE_FULL            0x00030000
+#define BNX2_CONDITION_PM_STATE_PREP            0x00020000
+#define BNX2_CONDITION_PM_STATE_UNPREP          0x00010000
 
 #define BNX2_BC_STATE_DEBUG_CMD                        0x1dc
 #define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE      0x42440000
index 26bc25bd465dc155bc36b785ae6053505e7e0190..acd494647f2584f1c1b2f648c13ec0d14fa2f530 100644 (file)
@@ -872,6 +872,8 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
        if (unlikely(bp->panic))
                return 0;
 #endif
+       if (budget <= 0)
+               return rx_pkt;
 
        bd_cons = fp->rx_bd_cons;
        bd_prod = fp->rx_bd_prod;
@@ -3875,7 +3877,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                                     xmit_type);
                }
 
-               /* Add the macs to the parsing BD this is a vf */
+               /* Add the macs to the parsing BD if this is a vf or if
+                * Tx Switching is enabled.
+                */
                if (IS_VF(bp)) {
                        /* override GRE parameters in BD */
                        bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
@@ -3883,6 +3887,11 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                              &pbd_e2->data.mac_addr.src_lo,
                                              eth->h_source);
 
+                       bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
+                                             &pbd_e2->data.mac_addr.dst_mid,
+                                             &pbd_e2->data.mac_addr.dst_lo,
+                                             eth->h_dest);
+               } else if (bp->flags & TX_SWITCHING) {
                        bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
                                              &pbd_e2->data.mac_addr.dst_mid,
                                              &pbd_e2->data.mac_addr.dst_lo,
index 6e5e7c0ffbd7ccbc5e52a5f4660d83d3aad7e5d1..bbbd2a4bc161c13a1cc4c5bd74c1773cf22d3332 100644 (file)
@@ -6593,7 +6593,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
                pkts_compl++;
                bytes_compl += skb->len;
 
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
 
                if (unlikely(tx_bug)) {
                        tg3_tx_recover(tp);
@@ -6843,8 +6843,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
 
                work_mask |= opaque_key;
 
-               if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
-                   (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) {
+               if (desc->err_vlan & RXD_ERR_MASK) {
                drop_it:
                        tg3_recycle_rx(tnapi, tpr, opaque_key,
                                       desc_idx, *post_ptr);
@@ -6925,7 +6924,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
 
                if (len > (tp->dev->mtu + ETH_HLEN) &&
                    skb->protocol != htons(ETH_P_8021Q)) {
-                       dev_kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        goto drop_it_no_recycle;
                }
 
@@ -7808,7 +7807,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
                                          PCI_DMA_TODEVICE);
                /* Make sure the mapping succeeded */
                if (pci_dma_mapping_error(tp->pdev, new_addr)) {
-                       dev_kfree_skb(new_skb);
+                       dev_kfree_skb_any(new_skb);
                        ret = -1;
                } else {
                        u32 save_entry = *entry;
@@ -7823,13 +7822,13 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
                                            new_skb->len, base_flags,
                                            mss, vlan)) {
                                tg3_tx_skb_unmap(tnapi, save_entry, -1);
-                               dev_kfree_skb(new_skb);
+                               dev_kfree_skb_any(new_skb);
                                ret = -1;
                        }
                }
        }
 
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        *pskb = new_skb;
        return ret;
 }
@@ -7872,7 +7871,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
        } while (segs);
 
 tg3_tso_bug_end:
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
@@ -8094,7 +8093,7 @@ dma_error:
        tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, --i);
        tnapi->tx_buffers[tnapi->tx_prod].skb = NULL;
 drop:
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 drop_nofree:
        tp->tx_dropped++;
        return NETDEV_TX_OK;
index ef472385bce47dcea87f43e48f202ffabbddf16d..04321e5a356e45a0f7fc642f3817035d983dbd90 100644 (file)
@@ -2608,7 +2608,11 @@ struct tg3_rx_buffer_desc {
 #define RXD_ERR_TOO_SMALL              0x00400000
 #define RXD_ERR_NO_RESOURCES           0x00800000
 #define RXD_ERR_HUGE_FRAME             0x01000000
-#define RXD_ERR_MASK                   0xffff0000
+
+#define RXD_ERR_MASK   (RXD_ERR_BAD_CRC | RXD_ERR_COLLISION |          \
+                        RXD_ERR_LINK_LOST | RXD_ERR_PHY_DECODE |       \
+                        RXD_ERR_MAC_ABRT | RXD_ERR_TOO_SMALL |         \
+                        RXD_ERR_NO_RESOURCES | RXD_ERR_HUGE_FRAME)
 
        u32                             reserved;
        u32                             opaque;
index 1803c39590442d497d1cc7f543ef8148ac7e56ec..354ae9792badb329e89b0ab37f59ff78c73efd11 100644 (file)
@@ -1704,7 +1704,7 @@ bfa_flash_sem_get(void __iomem *bar)
        while (!bfa_raw_sem_get(bar)) {
                if (--n <= 0)
                        return BFA_STATUS_BADFLASH;
-               udelay(10000);
+               mdelay(10);
        }
        return BFA_STATUS_OK;
 }
index bf436d0a10949b0575754abe6fb3edb60a4b49aa..cb7625366ec2fc51c2a2a22cfc49307779cf36ad 100644 (file)
@@ -707,7 +707,8 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
                else
                        skb_checksum_none_assert(skb);
 
-               if (flags & BNA_CQ_EF_VLAN)
+               if ((flags & BNA_CQ_EF_VLAN) &&
+                   (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
                        __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cmpl->vlan_tag));
 
                if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type))
@@ -2094,7 +2095,9 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
                rx_config->q1_buf_size = BFI_SMALL_RXBUF_SIZE;
        }
 
-       rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED;
+       rx_config->vlan_strip_status =
+               (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) ?
+               BNA_STATUS_T_ENABLED : BNA_STATUS_T_DISABLED;
 }
 
 static void
@@ -2842,13 +2845,11 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
                }
                if (unlikely((gso_size + skb_transport_offset(skb) +
                              tcp_hdrlen(skb)) >= skb->len)) {
-                       txqent->hdr.wi.opcode =
-                               __constant_htons(BNA_TXQ_WI_SEND);
+                       txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND);
                        txqent->hdr.wi.lso_mss = 0;
                        BNAD_UPDATE_CTR(bnad, tx_skb_tso_too_short);
                } else {
-                       txqent->hdr.wi.opcode =
-                               __constant_htons(BNA_TXQ_WI_SEND_LSO);
+                       txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND_LSO);
                        txqent->hdr.wi.lso_mss = htons(gso_size);
                }
 
@@ -2862,7 +2863,7 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
                        htons(BNA_TXQ_WI_L4_HDR_N_OFFSET(
                        tcp_hdrlen(skb) >> 2, skb_transport_offset(skb)));
        } else  {
-               txqent->hdr.wi.opcode = __constant_htons(BNA_TXQ_WI_SEND);
+               txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND);
                txqent->hdr.wi.lso_mss = 0;
 
                if (unlikely(skb->len > (bnad->netdev->mtu + ETH_HLEN))) {
@@ -2873,11 +2874,10 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
                        u8 proto = 0;
 
-                       if (skb->protocol == __constant_htons(ETH_P_IP))
+                       if (skb->protocol == htons(ETH_P_IP))
                                proto = ip_hdr(skb)->protocol;
 #ifdef NETIF_F_IPV6_CSUM
-                       else if (skb->protocol ==
-                                __constant_htons(ETH_P_IPV6)) {
+                       else if (skb->protocol == htons(ETH_P_IPV6)) {
                                /* nexthdr may not be TCP immediately. */
                                proto = ipv6_hdr(skb)->nexthdr;
                        }
@@ -3059,8 +3059,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                        vect_id = 0;
                        BNA_QE_INDX_INC(prod, q_depth);
                        txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod];
-                       txqent->hdr.wi_ext.opcode =
-                               __constant_htons(BNA_TXQ_WI_EXTENSION);
+                       txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION);
                        unmap = &unmap_q[prod];
                }
 
@@ -3240,11 +3239,6 @@ bnad_set_rx_mode(struct net_device *netdev)
                        BNA_RXMODE_ALLMULTI;
        bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask, NULL);
 
-       if (bnad->cfg_flags & BNAD_CF_PROMISC)
-               bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
-       else
-               bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
-
        spin_unlock_irqrestore(&bnad->bna_lock, flags);
 }
 
@@ -3369,6 +3363,27 @@ bnad_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
        return 0;
 }
 
+static int bnad_set_features(struct net_device *dev, netdev_features_t features)
+{
+       struct bnad *bnad = netdev_priv(dev);
+       netdev_features_t changed = features ^ dev->features;
+
+       if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && netif_running(dev)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&bnad->bna_lock, flags);
+
+               if (features & NETIF_F_HW_VLAN_CTAG_RX)
+                       bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
+               else
+                       bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
+
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       }
+
+       return 0;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void
 bnad_netpoll(struct net_device *netdev)
@@ -3416,6 +3431,7 @@ static const struct net_device_ops bnad_netdev_ops = {
        .ndo_change_mtu         = bnad_change_mtu,
        .ndo_vlan_rx_add_vid    = bnad_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = bnad_vlan_rx_kill_vid,
+       .ndo_set_features       = bnad_set_features,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = bnad_netpoll
 #endif
@@ -3428,14 +3444,14 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac)
 
        netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-               NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX;
+               NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX |
+               NETIF_F_HW_VLAN_CTAG_RX;
 
        netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                NETIF_F_TSO | NETIF_F_TSO6;
 
-       netdev->features |= netdev->hw_features |
-               NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
+       netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
 
        if (using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
index 3190d38e16fbd5d59a8cbc0cca7378a500572402..d0c38e01e99fdc70e802b33dc977e081d1a72f5c 100644 (file)
@@ -632,11 +632,16 @@ static void gem_rx_refill(struct macb *bp)
                                           "Unable to allocate sk_buff\n");
                                break;
                        }
-                       bp->rx_skbuff[entry] = skb;
 
                        /* now fill corresponding descriptor entry */
                        paddr = dma_map_single(&bp->pdev->dev, skb->data,
                                               bp->rx_buffer_size, DMA_FROM_DEVICE);
+                       if (dma_mapping_error(&bp->pdev->dev, paddr)) {
+                               dev_kfree_skb(skb);
+                               break;
+                       }
+
+                       bp->rx_skbuff[entry] = skb;
 
                        if (entry == RX_RING_SIZE - 1)
                                paddr |= MACB_BIT(RX_WRAP);
@@ -725,7 +730,7 @@ static int gem_rx(struct macb *bp, int budget)
                skb_put(skb, len);
                addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, addr));
                dma_unmap_single(&bp->pdev->dev, addr,
-                                len, DMA_FROM_DEVICE);
+                                bp->rx_buffer_size, DMA_FROM_DEVICE);
 
                skb->protocol = eth_type_trans(skb, bp->dev);
                skb_checksum_none_assert(skb);
@@ -1036,11 +1041,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        entry = macb_tx_ring_wrap(bp->tx_head);
-       bp->tx_head++;
        netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
        mapping = dma_map_single(&bp->pdev->dev, skb->data,
                                 len, DMA_TO_DEVICE);
+       if (dma_mapping_error(&bp->pdev->dev, mapping)) {
+               kfree_skb(skb);
+               goto unlock;
+       }
 
+       bp->tx_head++;
        tx_skb = &bp->tx_skb[entry];
        tx_skb->skb = skb;
        tx_skb->mapping = mapping;
@@ -1066,6 +1075,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1)
                netif_stop_queue(dev);
 
+unlock:
        spin_unlock_irqrestore(&bp->lock, flags);
 
        return NETDEV_TX_OK;
index 944f2cbc1795c763c5494dd471a80e83d78f0936..32db37709263bc14e596056bc7a9df80cc65bb62 100644 (file)
@@ -500,6 +500,7 @@ struct sge_txq {
        spinlock_t db_lock;
        int db_disabled;
        unsigned short db_pidx;
+       unsigned short db_pidx_inc;
        u64 udb;
 };
 
@@ -556,8 +557,13 @@ struct sge {
        u32 pktshift;               /* padding between CPL & packet data */
        u32 fl_align;               /* response queue message alignment */
        u32 fl_starve_thres;        /* Free List starvation threshold */
-       unsigned int starve_thres;
-       u8 idma_state[2];
+
+       /* State variables for detecting an SGE Ingress DMA hang */
+       unsigned int idma_1s_thresh;/* SGE same State Counter 1s threshold */
+       unsigned int idma_stalled[2];/* SGE synthesized stalled timers in HZ */
+       unsigned int idma_state[2]; /* SGE IDMA Hang detect state */
+       unsigned int idma_qid[2];   /* SGE IDMA Hung Ingress Queue ID */
+
        unsigned int egr_start;
        unsigned int ingr_start;
        void *egr_map[MAX_EGRQ];    /* qid->queue egress queue map */
@@ -1032,4 +1038,5 @@ void t4_db_dropped(struct adapter *adapter);
 int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len);
 int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
                         u32 addr, u32 val);
+void t4_sge_decode_idma_state(struct adapter *adapter, int state);
 #endif /* __CXGB4_H__ */
index da4edc1c77b376f380ed9bd2aa3de2994f5178e9..cc04d090354cc686c52d69c4125c5222e7a3a2cd 100644 (file)
@@ -3578,14 +3578,25 @@ static void drain_db_fifo(struct adapter *adap, int usecs)
 
 static void disable_txq_db(struct sge_txq *q)
 {
-       spin_lock_irq(&q->db_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&q->db_lock, flags);
        q->db_disabled = 1;
-       spin_unlock_irq(&q->db_lock);
+       spin_unlock_irqrestore(&q->db_lock, flags);
 }
 
-static void enable_txq_db(struct sge_txq *q)
+static void enable_txq_db(struct adapter *adap, struct sge_txq *q)
 {
        spin_lock_irq(&q->db_lock);
+       if (q->db_pidx_inc) {
+               /* Make sure that all writes to the TX descriptors
+                * are committed before we tell HW about them.
+                */
+               wmb();
+               t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
+                            QID(q->cntxt_id) | PIDX(q->db_pidx_inc));
+               q->db_pidx_inc = 0;
+       }
        q->db_disabled = 0;
        spin_unlock_irq(&q->db_lock);
 }
@@ -3607,11 +3618,32 @@ static void enable_dbs(struct adapter *adap)
        int i;
 
        for_each_ethrxq(&adap->sge, i)
-               enable_txq_db(&adap->sge.ethtxq[i].q);
+               enable_txq_db(adap, &adap->sge.ethtxq[i].q);
        for_each_ofldrxq(&adap->sge, i)
-               enable_txq_db(&adap->sge.ofldtxq[i].q);
+               enable_txq_db(adap, &adap->sge.ofldtxq[i].q);
        for_each_port(adap, i)
-               enable_txq_db(&adap->sge.ctrlq[i].q);
+               enable_txq_db(adap, &adap->sge.ctrlq[i].q);
+}
+
+static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd)
+{
+       if (adap->uld_handle[CXGB4_ULD_RDMA])
+               ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA],
+                               cmd);
+}
+
+static void process_db_full(struct work_struct *work)
+{
+       struct adapter *adap;
+
+       adap = container_of(work, struct adapter, db_full_task);
+
+       drain_db_fifo(adap, dbfifo_drain_delay);
+       enable_dbs(adap);
+       notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
+       t4_set_reg_field(adap, SGE_INT_ENABLE3,
+                        DBFIFO_HP_INT | DBFIFO_LP_INT,
+                        DBFIFO_HP_INT | DBFIFO_LP_INT);
 }
 
 static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
@@ -3619,7 +3651,7 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
        u16 hw_pidx, hw_cidx;
        int ret;
 
-       spin_lock_bh(&q->db_lock);
+       spin_lock_irq(&q->db_lock);
        ret = read_eq_indices(adap, (u16)q->cntxt_id, &hw_pidx, &hw_cidx);
        if (ret)
                goto out;
@@ -3636,7 +3668,8 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
        }
 out:
        q->db_disabled = 0;
-       spin_unlock_bh(&q->db_lock);
+       q->db_pidx_inc = 0;
+       spin_unlock_irq(&q->db_lock);
        if (ret)
                CH_WARN(adap, "DB drop recovery failed.\n");
 }
@@ -3652,29 +3685,6 @@ static void recover_all_queues(struct adapter *adap)
                sync_txq_pidx(adap, &adap->sge.ctrlq[i].q);
 }
 
-static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd)
-{
-       mutex_lock(&uld_mutex);
-       if (adap->uld_handle[CXGB4_ULD_RDMA])
-               ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA],
-                               cmd);
-       mutex_unlock(&uld_mutex);
-}
-
-static void process_db_full(struct work_struct *work)
-{
-       struct adapter *adap;
-
-       adap = container_of(work, struct adapter, db_full_task);
-
-       notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
-       drain_db_fifo(adap, dbfifo_drain_delay);
-       t4_set_reg_field(adap, SGE_INT_ENABLE3,
-                        DBFIFO_HP_INT | DBFIFO_LP_INT,
-                        DBFIFO_HP_INT | DBFIFO_LP_INT);
-       notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
-}
-
 static void process_db_drop(struct work_struct *work)
 {
        struct adapter *adap;
@@ -3682,11 +3692,13 @@ static void process_db_drop(struct work_struct *work)
        adap = container_of(work, struct adapter, db_drop_task);
 
        if (is_t4(adap->params.chip)) {
-               disable_dbs(adap);
+               drain_db_fifo(adap, dbfifo_drain_delay);
                notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP);
-               drain_db_fifo(adap, 1);
+               drain_db_fifo(adap, dbfifo_drain_delay);
                recover_all_queues(adap);
+               drain_db_fifo(adap, dbfifo_drain_delay);
                enable_dbs(adap);
+               notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
        } else {
                u32 dropped_db = t4_read_reg(adap, 0x010ac);
                u16 qid = (dropped_db >> 15) & 0x1ffff;
@@ -3727,6 +3739,8 @@ static void process_db_drop(struct work_struct *work)
 void t4_db_full(struct adapter *adap)
 {
        if (is_t4(adap->params.chip)) {
+               disable_dbs(adap);
+               notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
                t4_set_reg_field(adap, SGE_INT_ENABLE3,
                                 DBFIFO_HP_INT | DBFIFO_LP_INT, 0);
                queue_work(workq, &adap->db_full_task);
@@ -3735,8 +3749,11 @@ void t4_db_full(struct adapter *adap)
 
 void t4_db_dropped(struct adapter *adap)
 {
-       if (is_t4(adap->params.chip))
-               queue_work(workq, &adap->db_drop_task);
+       if (is_t4(adap->params.chip)) {
+               disable_dbs(adap);
+               notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
+       }
+       queue_work(workq, &adap->db_drop_task);
 }
 
 static void uld_attach(struct adapter *adap, unsigned int uld)
@@ -6206,6 +6223,7 @@ static struct pci_driver cxgb4_driver = {
        .id_table = cxgb4_pci_tbl,
        .probe    = init_one,
        .remove   = remove_one,
+       .shutdown = remove_one,
        .err_handler = &cxgb4_eeh,
 };
 
index af76b25bb6064b202738c2720120eb1de7718d7a..d4db382ff8c7918e956bf0378fd6db56e81e6859 100644 (file)
  */
 #define TX_QCHECK_PERIOD (HZ / 2)
 
+/* SGE Hung Ingress DMA Threshold Warning time (in Hz) and Warning Repeat Rate
+ * (in RX_QCHECK_PERIOD multiples).  If we find one of the SGE Ingress DMA
+ * State Machines in the same state for this amount of time (in HZ) then we'll
+ * issue a warning about a potential hang.  We'll repeat the warning as the
+ * SGE Ingress DMA Channel appears to be hung every N RX_QCHECK_PERIODs till
+ * the situation clears.  If the situation clears, we'll note that as well.
+ */
+#define SGE_IDMA_WARN_THRESH (1 * HZ)
+#define SGE_IDMA_WARN_REPEAT (20 * RX_QCHECK_PERIOD)
+
 /*
  * Max number of Tx descriptors to be reclaimed by the Tx timer.
  */
@@ -850,9 +860,10 @@ static void cxgb_pio_copy(u64 __iomem *dst, u64 *src)
 static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
 {
        unsigned int *wr, index;
+       unsigned long flags;
 
        wmb();            /* write descriptors before telling HW */
-       spin_lock(&q->db_lock);
+       spin_lock_irqsave(&q->db_lock, flags);
        if (!q->db_disabled) {
                if (is_t4(adap->params.chip)) {
                        t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
@@ -868,9 +879,10 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
                                writel(n,  adap->bar2 + q->udb + 8);
                        wmb();
                }
-       }
+       } else
+               q->db_pidx_inc += n;
        q->db_pidx = q->pidx;
-       spin_unlock(&q->db_lock);
+       spin_unlock_irqrestore(&q->db_lock, flags);
 }
 
 /**
@@ -1041,7 +1053,6 @@ out_free: dev_kfree_skb(skb);
        end = (u64 *)wr + flits;
 
        len = immediate ? skb->len : 0;
-       len += sizeof(*cpl);
        ssi = skb_shinfo(skb);
        if (ssi->gso_size) {
                struct cpl_tx_pkt_lso *lso = (void *)wr;
@@ -1069,6 +1080,7 @@ out_free: dev_kfree_skb(skb);
                q->tso++;
                q->tx_cso += ssi->gso_segs;
        } else {
+               len += sizeof(*cpl);
                wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
                                       FW_WR_IMMDLEN(len));
                cpl = (void *)(wr + 1);
@@ -2008,7 +2020,7 @@ irq_handler_t t4_intr_handler(struct adapter *adap)
 static void sge_rx_timer_cb(unsigned long data)
 {
        unsigned long m;
-       unsigned int i, cnt[2];
+       unsigned int i, idma_same_state_cnt[2];
        struct adapter *adap = (struct adapter *)data;
        struct sge *s = &adap->sge;
 
@@ -2031,21 +2043,64 @@ static void sge_rx_timer_cb(unsigned long data)
                }
 
        t4_write_reg(adap, SGE_DEBUG_INDEX, 13);
-       cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH);
-       cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
-
-       for (i = 0; i < 2; i++)
-               if (cnt[i] >= s->starve_thres) {
-                       if (s->idma_state[i] || cnt[i] == 0xffffffff)
-                               continue;
-                       s->idma_state[i] = 1;
-                       t4_write_reg(adap, SGE_DEBUG_INDEX, 11);
-                       m = t4_read_reg(adap, SGE_DEBUG_DATA_LOW) >> (i * 16);
-                       dev_warn(adap->pdev_dev,
-                                "SGE idma%u starvation detected for "
-                                "queue %lu\n", i, m & 0xffff);
-               } else if (s->idma_state[i])
-                       s->idma_state[i] = 0;
+       idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH);
+       idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+
+       for (i = 0; i < 2; i++) {
+               u32 debug0, debug11;
+
+               /* If the Ingress DMA Same State Counter ("timer") is less
+                * than 1s, then we can reset our synthesized Stall Timer and
+                * continue.  If we have previously emitted warnings about a
+                * potential stalled Ingress Queue, issue a note indicating
+                * that the Ingress Queue has resumed forward progress.
+                */
+               if (idma_same_state_cnt[i] < s->idma_1s_thresh) {
+                       if (s->idma_stalled[i] >= SGE_IDMA_WARN_THRESH)
+                               CH_WARN(adap, "SGE idma%d, queue%u,resumed after %d sec\n",
+                                       i, s->idma_qid[i],
+                                       s->idma_stalled[i]/HZ);
+                       s->idma_stalled[i] = 0;
+                       continue;
+               }
+
+               /* Synthesize an SGE Ingress DMA Same State Timer in the Hz
+                * domain.  The first time we get here it'll be because we
+                * passed the 1s Threshold; each additional time it'll be
+                * because the RX Timer Callback is being fired on its regular
+                * schedule.
+                *
+                * If the stall is below our Potential Hung Ingress Queue
+                * Warning Threshold, continue.
+                */
+               if (s->idma_stalled[i] == 0)
+                       s->idma_stalled[i] = HZ;
+               else
+                       s->idma_stalled[i] += RX_QCHECK_PERIOD;
+
+               if (s->idma_stalled[i] < SGE_IDMA_WARN_THRESH)
+                       continue;
+
+               /* We'll issue a warning every SGE_IDMA_WARN_REPEAT Hz */
+               if (((s->idma_stalled[i] - HZ) % SGE_IDMA_WARN_REPEAT) != 0)
+                       continue;
+
+               /* Read and save the SGE IDMA State and Queue ID information.
+                * We do this every time in case it changes across time ...
+                */
+               t4_write_reg(adap, SGE_DEBUG_INDEX, 0);
+               debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+               s->idma_state[i] = (debug0 >> (i * 9)) & 0x3f;
+
+               t4_write_reg(adap, SGE_DEBUG_INDEX, 11);
+               debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+               s->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff;
+
+               CH_WARN(adap, "SGE idma%u, queue%u, maybe stuck state%u %dsecs (debug0=%#x, debug11=%#x)\n",
+                       i, s->idma_qid[i], s->idma_state[i],
+                       s->idma_stalled[i]/HZ, debug0, debug11);
+               t4_sge_decode_idma_state(adap, s->idma_state[i]);
+       }
 
        mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD);
 }
@@ -2596,11 +2651,19 @@ static int t4_sge_init_soft(struct adapter *adap)
        fl_small_mtu = READ_FL_BUF(RX_SMALL_MTU_BUF);
        fl_large_mtu = READ_FL_BUF(RX_LARGE_MTU_BUF);
 
+       /* We only bother using the Large Page logic if the Large Page Buffer
+        * is larger than our Page Size Buffer.
+        */
+       if (fl_large_pg <= fl_small_pg)
+               fl_large_pg = 0;
+
        #undef READ_FL_BUF
 
+       /* The Page Size Buffer must be exactly equal to our Page Size and the
+        * Large Page Size Buffer should be 0 (per above) or a power of 2.
+        */
        if (fl_small_pg != PAGE_SIZE ||
-           (fl_large_pg != 0 && (fl_large_pg < fl_small_pg ||
-                                 (fl_large_pg & (fl_large_pg-1)) != 0))) {
+           (fl_large_pg & (fl_large_pg-1)) != 0) {
                dev_err(adap->pdev_dev, "bad SGE FL page buffer sizes [%d, %d]\n",
                        fl_small_pg, fl_large_pg);
                return -EINVAL;
@@ -2715,8 +2778,8 @@ static int t4_sge_init_hard(struct adapter *adap)
 int t4_sge_init(struct adapter *adap)
 {
        struct sge *s = &adap->sge;
-       u32 sge_control;
-       int ret;
+       u32 sge_control, sge_conm_ctrl;
+       int ret, egress_threshold;
 
        /*
         * Ingress Padding Boundary and Egress Status Page Size are set up by
@@ -2741,15 +2804,24 @@ int t4_sge_init(struct adapter *adap)
         * SGE's Egress Congestion Threshold.  If it isn't, then we can get
         * stuck waiting for new packets while the SGE is waiting for us to
         * give it more Free List entries.  (Note that the SGE's Egress
-        * Congestion Threshold is in units of 2 Free List pointers.)
+        * Congestion Threshold is in units of 2 Free List pointers.) For T4,
+        * there was only a single field to control this.  For T5 there's the
+        * original field which now only applies to Unpacked Mode Free List
+        * buffers and a new field which only applies to Packed Mode Free List
+        * buffers.
         */
-       s->fl_starve_thres
-               = EGRTHRESHOLD_GET(t4_read_reg(adap, SGE_CONM_CTRL))*2 + 1;
+       sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL);
+       if (is_t4(adap->params.chip))
+               egress_threshold = EGRTHRESHOLD_GET(sge_conm_ctrl);
+       else
+               egress_threshold = EGRTHRESHOLDPACKING_GET(sge_conm_ctrl);
+       s->fl_starve_thres = 2*egress_threshold + 1;
 
        setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap);
        setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap);
-       s->starve_thres = core_ticks_per_usec(adap) * 1000000;  /* 1 s */
-       s->idma_state[0] = s->idma_state[1] = 0;
+       s->idma_1s_thresh = core_ticks_per_usec(adap) * 1000000;  /* 1 s */
+       s->idma_stalled[0] = 0;
+       s->idma_stalled[1] = 0;
        spin_lock_init(&s->intrq_lock);
 
        return 0;
index d3c2a516fa886b300e305224c5b8c85f7473f145..fb2fe65903c2b7675701e1911a53b6e484566a73 100644 (file)
@@ -2596,6 +2596,112 @@ int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
        return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
 }
 
+/**
+ *     t4_sge_decode_idma_state - decode the idma state
+ *     @adap: the adapter
+ *     @state: the state idma is stuck in
+ */
+void t4_sge_decode_idma_state(struct adapter *adapter, int state)
+{
+       static const char * const t4_decode[] = {
+               "IDMA_IDLE",
+               "IDMA_PUSH_MORE_CPL_FIFO",
+               "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO",
+               "Not used",
+               "IDMA_PHYSADDR_SEND_PCIEHDR",
+               "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST",
+               "IDMA_PHYSADDR_SEND_PAYLOAD",
+               "IDMA_SEND_FIFO_TO_IMSG",
+               "IDMA_FL_REQ_DATA_FL_PREP",
+               "IDMA_FL_REQ_DATA_FL",
+               "IDMA_FL_DROP",
+               "IDMA_FL_H_REQ_HEADER_FL",
+               "IDMA_FL_H_SEND_PCIEHDR",
+               "IDMA_FL_H_PUSH_CPL_FIFO",
+               "IDMA_FL_H_SEND_CPL",
+               "IDMA_FL_H_SEND_IP_HDR_FIRST",
+               "IDMA_FL_H_SEND_IP_HDR",
+               "IDMA_FL_H_REQ_NEXT_HEADER_FL",
+               "IDMA_FL_H_SEND_NEXT_PCIEHDR",
+               "IDMA_FL_H_SEND_IP_HDR_PADDING",
+               "IDMA_FL_D_SEND_PCIEHDR",
+               "IDMA_FL_D_SEND_CPL_AND_IP_HDR",
+               "IDMA_FL_D_REQ_NEXT_DATA_FL",
+               "IDMA_FL_SEND_PCIEHDR",
+               "IDMA_FL_PUSH_CPL_FIFO",
+               "IDMA_FL_SEND_CPL",
+               "IDMA_FL_SEND_PAYLOAD_FIRST",
+               "IDMA_FL_SEND_PAYLOAD",
+               "IDMA_FL_REQ_NEXT_DATA_FL",
+               "IDMA_FL_SEND_NEXT_PCIEHDR",
+               "IDMA_FL_SEND_PADDING",
+               "IDMA_FL_SEND_COMPLETION_TO_IMSG",
+               "IDMA_FL_SEND_FIFO_TO_IMSG",
+               "IDMA_FL_REQ_DATAFL_DONE",
+               "IDMA_FL_REQ_HEADERFL_DONE",
+       };
+       static const char * const t5_decode[] = {
+               "IDMA_IDLE",
+               "IDMA_ALMOST_IDLE",
+               "IDMA_PUSH_MORE_CPL_FIFO",
+               "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO",
+               "IDMA_SGEFLRFLUSH_SEND_PCIEHDR",
+               "IDMA_PHYSADDR_SEND_PCIEHDR",
+               "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST",
+               "IDMA_PHYSADDR_SEND_PAYLOAD",
+               "IDMA_SEND_FIFO_TO_IMSG",
+               "IDMA_FL_REQ_DATA_FL",
+               "IDMA_FL_DROP",
+               "IDMA_FL_DROP_SEND_INC",
+               "IDMA_FL_H_REQ_HEADER_FL",
+               "IDMA_FL_H_SEND_PCIEHDR",
+               "IDMA_FL_H_PUSH_CPL_FIFO",
+               "IDMA_FL_H_SEND_CPL",
+               "IDMA_FL_H_SEND_IP_HDR_FIRST",
+               "IDMA_FL_H_SEND_IP_HDR",
+               "IDMA_FL_H_REQ_NEXT_HEADER_FL",
+               "IDMA_FL_H_SEND_NEXT_PCIEHDR",
+               "IDMA_FL_H_SEND_IP_HDR_PADDING",
+               "IDMA_FL_D_SEND_PCIEHDR",
+               "IDMA_FL_D_SEND_CPL_AND_IP_HDR",
+               "IDMA_FL_D_REQ_NEXT_DATA_FL",
+               "IDMA_FL_SEND_PCIEHDR",
+               "IDMA_FL_PUSH_CPL_FIFO",
+               "IDMA_FL_SEND_CPL",
+               "IDMA_FL_SEND_PAYLOAD_FIRST",
+               "IDMA_FL_SEND_PAYLOAD",
+               "IDMA_FL_REQ_NEXT_DATA_FL",
+               "IDMA_FL_SEND_NEXT_PCIEHDR",
+               "IDMA_FL_SEND_PADDING",
+               "IDMA_FL_SEND_COMPLETION_TO_IMSG",
+       };
+       static const u32 sge_regs[] = {
+               SGE_DEBUG_DATA_LOW_INDEX_2,
+               SGE_DEBUG_DATA_LOW_INDEX_3,
+               SGE_DEBUG_DATA_HIGH_INDEX_10,
+       };
+       const char **sge_idma_decode;
+       int sge_idma_decode_nstates;
+       int i;
+
+       if (is_t4(adapter->params.chip)) {
+               sge_idma_decode = (const char **)t4_decode;
+               sge_idma_decode_nstates = ARRAY_SIZE(t4_decode);
+       } else {
+               sge_idma_decode = (const char **)t5_decode;
+               sge_idma_decode_nstates = ARRAY_SIZE(t5_decode);
+       }
+
+       if (state < sge_idma_decode_nstates)
+               CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]);
+       else
+               CH_WARN(adapter, "idma state %d unknown\n", state);
+
+       for (i = 0; i < ARRAY_SIZE(sge_regs); i++)
+               CH_WARN(adapter, "SGE register %#x value %#x\n",
+                       sge_regs[i], t4_read_reg(adapter, sge_regs[i]));
+}
+
 /**
  *      t4_fw_hello - establish communication with FW
  *      @adap: the adapter
index cd6874b571ee2585c3ef1c9f8c418c7c643b8d46..f2738c7107898f2cf9112c74e33edc2f5ab16053 100644 (file)
@@ -116,6 +116,7 @@ enum CPL_error {
        CPL_ERR_KEEPALIVE_TIMEDOUT = 34,
        CPL_ERR_RTX_NEG_ADVICE     = 35,
        CPL_ERR_PERSIST_NEG_ADVICE = 36,
+       CPL_ERR_KEEPALV_NEG_ADVICE = 37,
        CPL_ERR_ABORT_FAILED       = 42,
        CPL_ERR_IWARP_FLM          = 50,
 };
index 4082522d81408bf0a23cff8eaf9700bef14533a9..225ad8a5722de026bf0302b4f4f49886100e66f5 100644 (file)
 #define  EGRTHRESHOLD(x)     ((x) << EGRTHRESHOLDshift)
 #define  EGRTHRESHOLD_GET(x) (((x) & EGRTHRESHOLD_MASK) >> EGRTHRESHOLDshift)
 
+#define EGRTHRESHOLDPACKING_MASK       0x3fU
+#define EGRTHRESHOLDPACKING_SHIFT      14
+#define EGRTHRESHOLDPACKING(x)         ((x) << EGRTHRESHOLDPACKING_SHIFT)
+#define EGRTHRESHOLDPACKING_GET(x)     (((x) >> EGRTHRESHOLDPACKING_SHIFT) & \
+                                         EGRTHRESHOLDPACKING_MASK)
+
 #define SGE_DBFIFO_STATUS 0x10a4
 #define  HP_INT_THRESH_SHIFT 28
 #define  HP_INT_THRESH_MASK  0xfU
 #define SGE_DEBUG_INDEX 0x10cc
 #define SGE_DEBUG_DATA_HIGH 0x10d0
 #define SGE_DEBUG_DATA_LOW 0x10d4
+#define SGE_DEBUG_DATA_LOW_INDEX_2     0x12c8
+#define SGE_DEBUG_DATA_LOW_INDEX_3     0x12cc
+#define SGE_DEBUG_DATA_HIGH_INDEX_10   0x12a8
 #define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4
 
 #define S_HP_INT_THRESH    28
index dcd58f23834ac3b67f9175f65a466987abce50ef..4c35fc8fad99f6d90dbbf925845ec672292a2a91 100644 (file)
@@ -1086,14 +1086,15 @@ static int enic_poll(struct napi_struct *napi, int budget)
        unsigned int intr = enic_legacy_io_intr();
        unsigned int rq_work_to_do = budget;
        unsigned int wq_work_to_do = -1; /* no limit */
-       unsigned int  work_done, rq_work_done, wq_work_done;
+       unsigned int  work_done, rq_work_done = 0, wq_work_done;
        int err;
 
        /* Service RQ (first) and WQ
         */
 
-       rq_work_done = vnic_cq_service(&enic->cq[cq_rq],
-               rq_work_to_do, enic_rq_service, NULL);
+       if (budget > 0)
+               rq_work_done = vnic_cq_service(&enic->cq[cq_rq],
+                       rq_work_to_do, enic_rq_service, NULL);
 
        wq_work_done = vnic_cq_service(&enic->cq[cq_wq],
                wq_work_to_do, enic_wq_service, NULL);
@@ -1141,14 +1142,15 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
        unsigned int cq = enic_cq_rq(enic, rq);
        unsigned int intr = enic_msix_rq_intr(enic, rq);
        unsigned int work_to_do = budget;
-       unsigned int work_done;
+       unsigned int work_done = 0;
        int err;
 
        /* Service RQ
         */
 
-       work_done = vnic_cq_service(&enic->cq[cq],
-               work_to_do, enic_rq_service, NULL);
+       if (budget > 0)
+               work_done = vnic_cq_service(&enic->cq[cq],
+                       work_to_do, enic_rq_service, NULL);
 
        /* Return intr event credits for this polling
         * cycle.  An intr event is the completion of a
index bf5ca71df77fb014b8507d9890486bda35d42904..a587c8aa27ed865efa5a9a537c33043c7d745303 100644 (file)
@@ -34,7 +34,7 @@
 #include "be_hw.h"
 #include "be_roce.h"
 
-#define DRV_VER                        "10.0.600.0u"
+#define DRV_VER                        "10.2u"
 #define DRV_NAME               "be2net"
 #define BE_NAME                        "Emulex BladeEngine2"
 #define BE3_NAME               "Emulex BladeEngine3"
@@ -350,13 +350,16 @@ struct be_drv_stats {
        u32 roce_drops_crc;
 };
 
+/* A vlan-id of 0xFFFF must be used to clear transparent vlan-tagging */
+#define BE_RESET_VLAN_TAG_ID   0xFFFF
+
 struct be_vf_cfg {
        unsigned char mac_addr[ETH_ALEN];
        int if_handle;
        int pmac_id;
-       u16 def_vid;
        u16 vlan_tag;
        u32 tx_rate;
+       u32 plink_tracking;
 };
 
 enum vf_state {
index 72bde5d1c3581c83b8f010a43af0b3cd539db353..cf5afe72f12fb8c78b2747ea6f2a6502c60d240d 100644 (file)
@@ -202,8 +202,12 @@ static void be_async_link_state_process(struct be_adapter *adapter,
        /* When link status changes, link speed must be re-queried from FW */
        adapter->phy.link_speed = -1;
 
-       /* Ignore physical link event */
-       if (lancer_chip(adapter) &&
+       /* On BEx the FW does not send a separate link status
+        * notification for physical and logical link.
+        * On other chips just process the logical link
+        * status notification
+        */
+       if (!BEx_chip(adapter) &&
            !(evt->port_link_status & LOGICAL_LINK_STATUS_MASK))
                return;
 
@@ -211,7 +215,8 @@ static void be_async_link_state_process(struct be_adapter *adapter,
         * it may not be received in some cases.
         */
        if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT)
-               be_link_status_update(adapter, evt->port_link_status);
+               be_link_status_update(adapter,
+                                     evt->port_link_status & LINK_STATUS_MASK);
 }
 
 /* Grp5 CoS Priority evt */
@@ -239,10 +244,12 @@ static void be_async_grp5_qos_speed_process(struct be_adapter *adapter,
 static void be_async_grp5_pvid_state_process(struct be_adapter *adapter,
                struct be_async_event_grp5_pvid_state *evt)
 {
-       if (evt->enabled)
+       if (evt->enabled) {
                adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK;
-       else
+               dev_info(&adapter->pdev->dev, "LPVID: %d\n", adapter->pvid);
+       } else {
                adapter->pvid = 0;
+       }
 }
 
 static void be_async_grp5_evt_process(struct be_adapter *adapter,
@@ -3743,6 +3750,45 @@ err:
        return status;
 }
 
+int be_cmd_set_logical_link_config(struct be_adapter *adapter,
+                                  int link_state, u8 domain)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_set_ll_link *req;
+       int status;
+
+       if (BEx_chip(adapter) || lancer_chip(adapter))
+               return 0;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
+
+       req = embedded_payload(wrb);
+
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                              OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG,
+                              sizeof(*req), wrb, NULL);
+
+       req->hdr.version = 1;
+       req->hdr.domain = domain;
+
+       if (link_state == IFLA_VF_LINK_STATE_ENABLE)
+               req->link_config |= 1;
+
+       if (link_state == IFLA_VF_LINK_STATE_AUTO)
+               req->link_config |= 1 << PLINK_TRACK_SHIFT;
+
+       status = be_mcc_notify_wait(adapter);
+err:
+       spin_unlock_bh(&adapter->mcc_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 d0ab980f77ead8e0cb34ab2f04ba76648db4c00b..fda3e8851e1724d558ba6fca16ed28d9a2a6376b 100644 (file)
@@ -203,6 +203,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_GET_BEACON_STATE                 70
 #define OPCODE_COMMON_READ_TRANSRECV_DATA              73
 #define OPCODE_COMMON_GET_PORT_NAME                    77
+#define OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG          80
 #define OPCODE_COMMON_SET_INTERRUPT_ENABLE             89
 #define OPCODE_COMMON_SET_FN_PRIVILEGES                        100
 #define OPCODE_COMMON_GET_PHY_DETAILS                  102
@@ -1991,6 +1992,13 @@ struct be_cmd_resp_get_iface_list {
        struct be_if_desc if_desc;
 };
 
+/*************** Set logical link ********************/
+#define PLINK_TRACK_SHIFT      8
+struct be_cmd_req_set_ll_link {
+       struct be_cmd_req_hdr hdr;
+       u32 link_config; /* Bit 0: UP_DOWN, Bit 9: PLINK */
+};
+
 int be_pci_fnum_get(struct be_adapter *adapter);
 int be_fw_wait_ready(struct be_adapter *adapter);
 int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -2112,3 +2120,5 @@ 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);
 int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable);
+int be_cmd_set_logical_link_config(struct be_adapter *adapter,
+                                         int link_state, u8 domain);
index cf09d8faca84d808cc23d564a0e20cf0881dee56..15ba96cba65df1ba051cc3b2e49b72640d92c217 100644 (file)
@@ -357,10 +357,10 @@ be_get_ethtool_stats(struct net_device *netdev,
                struct be_rx_stats *stats = rx_stats(rxo);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->sync);
+                       start = u64_stats_fetch_begin_irq(&stats->sync);
                        data[base] = stats->rx_bytes;
                        data[base + 1] = stats->rx_pkts;
-               } while (u64_stats_fetch_retry_bh(&stats->sync, start));
+               } while (u64_stats_fetch_retry_irq(&stats->sync, start));
 
                for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) {
                        p = (u8 *)stats + et_rx_stats[i].offset;
@@ -373,19 +373,19 @@ be_get_ethtool_stats(struct net_device *netdev,
                struct be_tx_stats *stats = tx_stats(txo);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->sync_compl);
+                       start = u64_stats_fetch_begin_irq(&stats->sync_compl);
                        data[base] = stats->tx_compl;
-               } while (u64_stats_fetch_retry_bh(&stats->sync_compl, start));
+               } while (u64_stats_fetch_retry_irq(&stats->sync_compl, start));
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->sync);
+                       start = u64_stats_fetch_begin_irq(&stats->sync);
                        for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) {
                                p = (u8 *)stats + et_tx_stats[i].offset;
                                data[base + i] =
                                        (et_tx_stats[i].size == sizeof(u64)) ?
                                                *(u64 *)p : *(u32 *)p;
                        }
-               } while (u64_stats_fetch_retry_bh(&stats->sync, start));
+               } while (u64_stats_fetch_retry_irq(&stats->sync, start));
                base += ETHTOOL_TXSTATS_NUM;
        }
 }
@@ -802,16 +802,18 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
 
        if (test->flags & ETH_TEST_FL_OFFLINE) {
                if (be_loopback_test(adapter, BE_MAC_LOOPBACK,
-                                               &data[0]) != 0) {
+                                    &data[0]) != 0)
                        test->flags |= ETH_TEST_FL_FAILED;
-               }
+
                if (be_loopback_test(adapter, BE_PHY_LOOPBACK,
-                                               &data[1]) != 0) {
-                       test->flags |= ETH_TEST_FL_FAILED;
-               }
-               if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
-                                               &data[2]) != 0) {
+                                    &data[1]) != 0)
                        test->flags |= ETH_TEST_FL_FAILED;
+
+               if (test->flags & ETH_TEST_FL_EXTERNAL_LB) {
+                       if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
+                                            &data[2]) != 0)
+                               test->flags |= ETH_TEST_FL_FAILED;
+                       test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
                }
        }
 
index 34644969a4be07eae7b973451a164e4c0b9dd181..a61f967f9ca19ffea71c3d9e12ed8c06f06c0cd1 100644 (file)
@@ -591,10 +591,10 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev,
        for_all_rx_queues(adapter, rxo, i) {
                const struct be_rx_stats *rx_stats = rx_stats(rxo);
                do {
-                       start = u64_stats_fetch_begin_bh(&rx_stats->sync);
+                       start = u64_stats_fetch_begin_irq(&rx_stats->sync);
                        pkts = rx_stats(rxo)->rx_pkts;
                        bytes = rx_stats(rxo)->rx_bytes;
-               } while (u64_stats_fetch_retry_bh(&rx_stats->sync, start));
+               } while (u64_stats_fetch_retry_irq(&rx_stats->sync, start));
                stats->rx_packets += pkts;
                stats->rx_bytes += bytes;
                stats->multicast += rx_stats(rxo)->rx_mcast_pkts;
@@ -605,10 +605,10 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev,
        for_all_tx_queues(adapter, txo, i) {
                const struct be_tx_stats *tx_stats = tx_stats(txo);
                do {
-                       start = u64_stats_fetch_begin_bh(&tx_stats->sync);
+                       start = u64_stats_fetch_begin_irq(&tx_stats->sync);
                        pkts = tx_stats(txo)->tx_pkts;
                        bytes = tx_stats(txo)->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&tx_stats->sync, start));
+               } while (u64_stats_fetch_retry_irq(&tx_stats->sync, start));
                stats->tx_packets += pkts;
                stats->tx_bytes += bytes;
        }
@@ -652,7 +652,7 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status)
                adapter->flags |= BE_FLAGS_LINK_STATUS_INIT;
        }
 
-       if ((link_status & LINK_STATUS_MASK) == LINK_UP)
+       if (link_status)
                netif_carrier_on(netdev);
        else
                netif_carrier_off(netdev);
@@ -913,24 +913,14 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter,
        return BE3_chip(adapter) && be_ipv6_exthdr_check(skb);
 }
 
-static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
-                                          struct sk_buff *skb,
-                                          bool *skip_hw_vlan)
+static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
+                                                 struct sk_buff *skb,
+                                                 bool *skip_hw_vlan)
 {
        struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
        unsigned int eth_hdr_len;
        struct iphdr *ip;
 
-       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
-        * may cause a transmit stall on that port. So the work-around is to
-        * pad short packets (<= 32 bytes) to a 36-byte length.
-        */
-       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
-               if (skb_padto(skb, 36))
-                       goto tx_drop;
-               skb->len = 36;
-       }
-
        /* For padded packets, BE HW modifies tot_len field in IP header
         * incorrecly when VLAN tag is inserted by HW.
         * For padded packets, Lancer computes incorrect checksum.
@@ -959,7 +949,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
            vlan_tx_tag_present(skb)) {
                skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
                if (unlikely(!skb))
-                       goto tx_drop;
+                       goto err;
        }
 
        /* HW may lockup when VLAN HW tagging is requested on
@@ -981,15 +971,39 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
            be_vlan_tag_tx_chk(adapter, skb)) {
                skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
                if (unlikely(!skb))
-                       goto tx_drop;
+                       goto err;
        }
 
        return skb;
 tx_drop:
        dev_kfree_skb_any(skb);
+err:
        return NULL;
 }
 
+static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
+                                          struct sk_buff *skb,
+                                          bool *skip_hw_vlan)
+{
+       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or
+        * less may cause a transmit stall on that port. So the work-around is
+        * to pad short packets (<= 32 bytes) to a 36-byte length.
+        */
+       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
+               if (skb_padto(skb, 36))
+                       return NULL;
+               skb->len = 36;
+       }
+
+       if (BEx_chip(adapter) || lancer_chip(adapter)) {
+               skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan);
+               if (!skb)
+                       return NULL;
+       }
+
+       return skb;
+}
+
 static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -1124,7 +1138,10 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
 
        /* Packets with VID 0 are always received by Lancer by default */
        if (lancer_chip(adapter) && vid == 0)
-               goto ret;
+               return status;
+
+       if (adapter->vlan_tag[vid])
+               return status;
 
        adapter->vlan_tag[vid] = 1;
        adapter->vlans_added++;
@@ -1134,7 +1151,7 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
                adapter->vlans_added--;
                adapter->vlan_tag[vid] = 0;
        }
-ret:
+
        return status;
 }
 
@@ -1157,6 +1174,14 @@ ret:
        return status;
 }
 
+static void be_clear_promisc(struct be_adapter *adapter)
+{
+       adapter->promiscuous = false;
+       adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
+
+       be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
+}
+
 static void be_set_rx_mode(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -1170,9 +1195,7 @@ static void be_set_rx_mode(struct net_device *netdev)
 
        /* BE was previously in promiscuous mode; disable it */
        if (adapter->promiscuous) {
-               adapter->promiscuous = false;
-               be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
-
+               be_clear_promisc(adapter);
                if (adapter->vlans_added)
                        be_vid_config(adapter);
        }
@@ -1268,6 +1291,7 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
        vi->vlan = vf_cfg->vlan_tag & VLAN_VID_MASK;
        vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT;
        memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN);
+       vi->linkstate = adapter->vf_cfg[vf].plink_tracking;
 
        return 0;
 }
@@ -1287,24 +1311,20 @@ static int be_set_vf_vlan(struct net_device *netdev,
 
        if (vlan || qos) {
                vlan |= qos << VLAN_PRIO_SHIFT;
-               if (vf_cfg->vlan_tag != vlan) {
-                       /* If this is new value, program it. Else skip. */
-                       vf_cfg->vlan_tag = vlan;
+               if (vf_cfg->vlan_tag != vlan)
                        status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
                                                       vf_cfg->if_handle, 0);
-               }
        } else {
                /* Reset Transparent Vlan Tagging. */
-               vf_cfg->vlan_tag = 0;
-               vlan = vf_cfg->def_vid;
-               status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                                              vf_cfg->if_handle, 0);
+               status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
+                                              vf + 1, vf_cfg->if_handle, 0);
        }
 
-
-       if (status)
+       if (!status)
+               vf_cfg->vlan_tag = vlan;
+       else
                dev_info(&adapter->pdev->dev,
-                               "VLAN %d config on VF %d failed\n", vlan, vf);
+                        "VLAN %d config on VF %d failed\n", vlan, vf);
        return status;
 }
 
@@ -1338,6 +1358,24 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
                adapter->vf_cfg[vf].tx_rate = rate;
        return status;
 }
+static int be_set_vf_link_state(struct net_device *netdev, int vf,
+                               int link_state)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       int status;
+
+       if (!sriov_enabled(adapter))
+               return -EPERM;
+
+       if (vf >= adapter->num_vfs)
+               return -EINVAL;
+
+       status = be_cmd_set_logical_link_config(adapter, link_state, vf+1);
+       if (!status)
+               adapter->vf_cfg[vf].plink_tracking = link_state;
+
+       return status;
+}
 
 static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts,
                          ulong now)
@@ -1370,15 +1408,15 @@ static void be_eqd_update(struct be_adapter *adapter)
 
                rxo = &adapter->rx_obj[eqo->idx];
                do {
-                       start = u64_stats_fetch_begin_bh(&rxo->stats.sync);
+                       start = u64_stats_fetch_begin_irq(&rxo->stats.sync);
                        rx_pkts = rxo->stats.rx_pkts;
-               } while (u64_stats_fetch_retry_bh(&rxo->stats.sync, start));
+               } while (u64_stats_fetch_retry_irq(&rxo->stats.sync, start));
 
                txo = &adapter->tx_obj[eqo->idx];
                do {
-                       start = u64_stats_fetch_begin_bh(&txo->stats.sync);
+                       start = u64_stats_fetch_begin_irq(&txo->stats.sync);
                        tx_pkts = txo->stats.tx_reqs;
-               } while (u64_stats_fetch_retry_bh(&txo->stats.sync, start));
+               } while (u64_stats_fetch_retry_irq(&txo->stats.sync, start));
 
 
                /* Skip, if wrapped around or first calculation */
@@ -1881,7 +1919,7 @@ static u16 be_tx_compl_process(struct be_adapter *adapter,
                queue_tail_inc(txq);
        } while (cur_index != last_index);
 
-       kfree_skb(sent_skb);
+       dev_kfree_skb_any(sent_skb);
        return num_wrbs;
 }
 
@@ -3022,11 +3060,11 @@ static int be_vf_setup_init(struct be_adapter *adapter)
 
 static int be_vf_setup(struct be_adapter *adapter)
 {
+       struct device *dev = &adapter->pdev->dev;
        struct be_vf_cfg *vf_cfg;
-       u16 def_vlan, lnk_speed;
        int status, old_vfs, vf;
-       struct device *dev = &adapter->pdev->dev;
        u32 privileges;
+       u16 lnk_speed;
 
        old_vfs = pci_num_vf(adapter->pdev);
        if (old_vfs) {
@@ -3093,14 +3131,12 @@ static int be_vf_setup(struct be_adapter *adapter)
                if (!status)
                        vf_cfg->tx_rate = lnk_speed;
 
-               status = be_cmd_get_hsw_config(adapter, &def_vlan,
-                                              vf + 1, vf_cfg->if_handle, NULL);
-               if (status)
-                       goto err;
-               vf_cfg->def_vid = def_vlan;
-
-               if (!old_vfs)
+               if (!old_vfs) {
                        be_cmd_enable_vf(adapter, vf + 1);
+                       be_cmd_set_logical_link_config(adapter,
+                                                      IFLA_VF_LINK_STATE_AUTO,
+                                                      vf+1);
+               }
        }
 
        if (!old_vfs) {
@@ -3140,13 +3176,16 @@ static void BEx_get_resources(struct be_adapter *adapter,
 {
        struct pci_dev *pdev = adapter->pdev;
        bool use_sriov = false;
-       int max_vfs;
-
-       max_vfs = pci_sriov_get_totalvfs(pdev);
-
-       if (BE3_chip(adapter) && sriov_want(adapter)) {
-               res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0;
-               use_sriov = res->max_vfs;
+       int max_vfs = 0;
+
+       if (be_physfn(adapter) && BE3_chip(adapter)) {
+               be_cmd_get_profile_config(adapter, res, 0);
+               /* Some old versions of BE3 FW don't report max_vfs value */
+               if (res->max_vfs == 0) {
+                       max_vfs = pci_sriov_get_totalvfs(pdev);
+                       res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0;
+               }
+               use_sriov = res->max_vfs && sriov_want(adapter);
        }
 
        if (be_physfn(adapter))
@@ -3173,9 +3212,13 @@ static void BEx_get_resources(struct be_adapter *adapter,
 
        res->max_mcast_mac = BE_MAX_MC;
 
-       /* For BE3 1Gb ports, F/W does not properly support multiple TXQs */
-       if (BE2_chip(adapter) || use_sriov || be_is_mc(adapter) ||
-           !be_physfn(adapter) || (adapter->port_num > 1))
+       /* 1) For BE3 1Gb ports, FW does not support multiple TXQs
+        * 2) Create multiple TX rings on a BE3-R multi-channel interface
+        *    *only* if it is RSS-capable.
+        */
+       if (BE2_chip(adapter) || use_sriov ||  (adapter->port_num > 1) ||
+           !be_physfn(adapter) || (be_is_mc(adapter) &&
+           !(adapter->function_caps & BE_FUNCTION_CAPS_RSS)))
                res->max_tx_qs = 1;
        else
                res->max_tx_qs = BE3_MAX_TX_QS;
@@ -3187,7 +3230,7 @@ static void BEx_get_resources(struct be_adapter *adapter,
        res->max_rx_qs = res->max_rss_qs + 1;
 
        if (be_physfn(adapter))
-               res->max_evt_qs = (max_vfs > 0) ?
+               res->max_evt_qs = (res->max_vfs > 0) ?
                                        BE3_SRIOV_MAX_EVT_QS : BE3_MAX_EVT_QS;
        else
                res->max_evt_qs = 1;
@@ -3278,9 +3321,8 @@ static int be_get_config(struct be_adapter *adapter)
        if (status)
                return status;
 
-       /* primary mac needs 1 pmac entry */
-       adapter->pmac_id = kcalloc(be_max_uc(adapter) + 1, sizeof(u32),
-                                  GFP_KERNEL);
+       adapter->pmac_id = kcalloc(be_max_uc(adapter),
+                                  sizeof(*adapter->pmac_id), GFP_KERNEL);
        if (!adapter->pmac_id)
                return -ENOMEM;
 
@@ -3454,6 +3496,10 @@ static int be_setup(struct be_adapter *adapter)
                be_cmd_set_flow_control(adapter, adapter->tx_fc,
                                        adapter->rx_fc);
 
+       if (be_physfn(adapter))
+               be_cmd_set_logical_link_config(adapter,
+                                              IFLA_VF_LINK_STATE_AUTO, 0);
+
        if (sriov_want(adapter)) {
                if (be_max_vfs(adapter))
                        be_vf_setup(adapter);
@@ -4093,6 +4139,7 @@ static const struct net_device_ops be_netdev_ops = {
        .ndo_set_vf_vlan        = be_set_vf_vlan,
        .ndo_set_vf_tx_rate     = be_set_vf_tx_rate,
        .ndo_get_vf_config      = be_get_vf_config,
+       .ndo_set_vf_link_state  = be_set_vf_link_state,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = be_netpoll,
 #endif
index 903362a7b58435878d790b06d9bb2dadbcdede35..03a351300013c82999474fb411731f1487755550 100644 (file)
@@ -389,12 +389,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                        netdev_err(ndev, "Tx DMA memory map failed\n");
                return NETDEV_TX_OK;
        }
-       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
-        * it's the last BD of the frame, and to put the CRC on the end.
-        */
-       status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
-                       | BD_ENET_TX_LAST | BD_ENET_TX_TC);
-       bdp->cbd_sc = status;
 
        if (fep->bufdesc_ex) {
 
@@ -416,6 +410,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                }
        }
 
+       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
+        * it's the last BD of the frame, and to put the CRC on the end.
+        */
+       status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+                       | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+       bdp->cbd_sc = status;
+
        bdp_pre = fec_enet_get_prevdesc(bdp, fep);
        if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
            !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
@@ -527,13 +528,6 @@ fec_restart(struct net_device *ndev, int duplex)
        /* Clear any outstanding interrupt. */
        writel(0xffc00000, fep->hwp + FEC_IEVENT);
 
-       /* Setup multicast filter. */
-       set_multicast_list(ndev);
-#ifndef CONFIG_M5272
-       writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
-       writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
-#endif
-
        /* Set maximum receive buffer size. */
        writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
 
@@ -654,6 +648,13 @@ fec_restart(struct net_device *ndev, int duplex)
 
        writel(rcntl, fep->hwp + FEC_R_CNTRL);
 
+       /* Setup multicast filter. */
+       set_multicast_list(ndev);
+#ifndef CONFIG_M5272
+       writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
+       writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
+#endif
+
        if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
                /* enable ENET endian swap */
                ecntl |= (1 << 8);
index 62f042d4aaa93cc85e79b079272ac26150b263a3..dc80db41d6b3397388b0210283c4c7fd3ce07680 100644 (file)
@@ -91,6 +91,9 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
        u16 pkt_len, sc;
        int curidx;
 
+       if (budget <= 0)
+               return received;
+
        /*
         * First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
index c5b9320f76298678b94291040c7412ae458dc5ea..6e12f936585621c64f1fa4a560566e75186216a4 100644 (file)
@@ -128,8 +128,10 @@ static void free_skb_resources(struct gfar_private *priv);
 static void gfar_set_multi(struct net_device *dev);
 static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
 static void gfar_configure_serdes(struct net_device *dev);
-static int gfar_poll(struct napi_struct *napi, int budget);
-static int gfar_poll_sq(struct napi_struct *napi, int budget);
+static int gfar_poll_rx(struct napi_struct *napi, int budget);
+static int gfar_poll_tx(struct napi_struct *napi, int budget);
+static int gfar_poll_rx_sq(struct napi_struct *napi, int budget);
+static int gfar_poll_tx_sq(struct napi_struct *napi, int budget);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void gfar_netpoll(struct net_device *dev);
 #endif
@@ -361,7 +363,10 @@ static void gfar_mac_rx_config(struct gfar_private *priv)
        if (priv->rx_filer_enable) {
                rctrl |= RCTRL_FILREN;
                /* Program the RIR0 reg with the required distribution */
-               gfar_write(&regs->rir0, DEFAULT_RIR0);
+               if (priv->poll_mode == GFAR_SQ_POLLING)
+                       gfar_write(&regs->rir0, DEFAULT_2RXQ_RIR0);
+               else /* GFAR_MQ_POLLING */
+                       gfar_write(&regs->rir0, DEFAULT_8RXQ_RIR0);
        }
 
        /* Restore PROMISC mode */
@@ -614,23 +619,26 @@ static void disable_napi(struct gfar_private *priv)
 {
        int i;
 
-       for (i = 0; i < priv->num_grps; i++)
-               napi_disable(&priv->gfargrp[i].napi);
+       for (i = 0; i < priv->num_grps; i++) {
+               napi_disable(&priv->gfargrp[i].napi_rx);
+               napi_disable(&priv->gfargrp[i].napi_tx);
+       }
 }
 
 static void enable_napi(struct gfar_private *priv)
 {
        int i;
 
-       for (i = 0; i < priv->num_grps; i++)
-               napi_enable(&priv->gfargrp[i].napi);
+       for (i = 0; i < priv->num_grps; i++) {
+               napi_enable(&priv->gfargrp[i].napi_rx);
+               napi_enable(&priv->gfargrp[i].napi_tx);
+       }
 }
 
 static int gfar_parse_group(struct device_node *np,
                            struct gfar_private *priv, const char *model)
 {
        struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];
-       u32 *queue_mask;
        int i;
 
        for (i = 0; i < GFAR_NUM_IRQS; i++) {
@@ -659,12 +667,20 @@ static int gfar_parse_group(struct device_node *np,
        grp->priv = priv;
        spin_lock_init(&grp->grplock);
        if (priv->mode == MQ_MG_MODE) {
-               queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
-               grp->rx_bit_map = queue_mask ?
-                       *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
-               queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
-               grp->tx_bit_map = queue_mask ?
-                       *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
+               u32 *rxq_mask, *txq_mask;
+               rxq_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
+               txq_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
+
+               if (priv->poll_mode == GFAR_SQ_POLLING) {
+                       /* One Q per interrupt group: Q0 to G0, Q1 to G1 */
+                       grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
+                       grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
+               } else { /* GFAR_MQ_POLLING */
+                       grp->rx_bit_map = rxq_mask ?
+                       *rxq_mask : (DEFAULT_MAPPING >> priv->num_grps);
+                       grp->tx_bit_map = txq_mask ?
+                       *txq_mask : (DEFAULT_MAPPING >> priv->num_grps);
+               }
        } else {
                grp->rx_bit_map = 0xFF;
                grp->tx_bit_map = 0xFF;
@@ -680,6 +696,8 @@ static int gfar_parse_group(struct device_node *np,
         * also assign queues to groups
         */
        for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) {
+               if (!grp->rx_queue)
+                       grp->rx_queue = priv->rx_queue[i];
                grp->num_rx_queues++;
                grp->rstat |= (RSTAT_CLEAR_RHALT >> i);
                priv->rqueue |= ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
@@ -687,6 +705,8 @@ static int gfar_parse_group(struct device_node *np,
        }
 
        for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) {
+               if (!grp->tx_queue)
+                       grp->tx_queue = priv->tx_queue[i];
                grp->num_tx_queues++;
                grp->tstat |= (TSTAT_CLEAR_THALT >> i);
                priv->tqueue |= (TQUEUE_EN0 >> i);
@@ -713,13 +733,35 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
        const u32 *stash_idx;
        unsigned int num_tx_qs, num_rx_qs;
        u32 *tx_queues, *rx_queues;
+       unsigned short mode, poll_mode;
 
        if (!np || !of_device_is_available(np))
                return -ENODEV;
 
-       /* parse the num of tx and rx queues */
+       if (of_device_is_compatible(np, "fsl,etsec2")) {
+               mode = MQ_MG_MODE;
+               poll_mode = GFAR_SQ_POLLING;
+       } else {
+               mode = SQ_SG_MODE;
+               poll_mode = GFAR_SQ_POLLING;
+       }
+
+       /* parse the num of HW tx and rx queues */
        tx_queues = (u32 *)of_get_property(np, "fsl,num_tx_queues", NULL);
-       num_tx_qs = tx_queues ? *tx_queues : 1;
+       rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL);
+
+       if (mode == SQ_SG_MODE) {
+               num_tx_qs = 1;
+               num_rx_qs = 1;
+       } else { /* MQ_MG_MODE */
+               if (poll_mode == GFAR_SQ_POLLING) {
+                       num_tx_qs = 2; /* one txq per int group */
+                       num_rx_qs = 2; /* one rxq per int group */
+               } else { /* GFAR_MQ_POLLING */
+                       num_tx_qs = tx_queues ? *tx_queues : 1;
+                       num_rx_qs = rx_queues ? *rx_queues : 1;
+               }
+       }
 
        if (num_tx_qs > MAX_TX_QS) {
                pr_err("num_tx_qs(=%d) greater than MAX_TX_QS(=%d)\n",
@@ -728,9 +770,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                return -EINVAL;
        }
 
-       rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL);
-       num_rx_qs = rx_queues ? *rx_queues : 1;
-
        if (num_rx_qs > MAX_RX_QS) {
                pr_err("num_rx_qs(=%d) greater than MAX_RX_QS(=%d)\n",
                       num_rx_qs, MAX_RX_QS);
@@ -746,6 +785,9 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
        priv = netdev_priv(dev);
        priv->ndev = dev;
 
+       priv->mode = mode;
+       priv->poll_mode = poll_mode;
+
        priv->num_tx_queues = num_tx_qs;
        netif_set_real_num_rx_queues(dev, num_rx_qs);
        priv->num_rx_queues = num_rx_qs;
@@ -769,15 +811,13 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                priv->gfargrp[i].regs = NULL;
 
        /* Parse and initialize group specific information */
-       if (of_device_is_compatible(np, "fsl,etsec2")) {
-               priv->mode = MQ_MG_MODE;
+       if (priv->mode == MQ_MG_MODE) {
                for_each_child_of_node(np, child) {
                        err = gfar_parse_group(child, priv, model);
                        if (err)
                                goto err_grp_init;
                }
-       } else {
-               priv->mode = SQ_SG_MODE;
+       } else { /* SQ_SG_MODE */
                err = gfar_parse_group(np, priv, model);
                if (err)
                        goto err_grp_init;
@@ -1257,13 +1297,19 @@ static int gfar_probe(struct platform_device *ofdev)
        dev->ethtool_ops = &gfar_ethtool_ops;
 
        /* Register for napi ...We are registering NAPI for each grp */
-       if (priv->mode == SQ_SG_MODE)
-               netif_napi_add(dev, &priv->gfargrp[0].napi, gfar_poll_sq,
-                              GFAR_DEV_WEIGHT);
-       else
-               for (i = 0; i < priv->num_grps; i++)
-                       netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll,
-                                      GFAR_DEV_WEIGHT);
+       for (i = 0; i < priv->num_grps; i++) {
+               if (priv->poll_mode == GFAR_SQ_POLLING) {
+                       netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
+                                      gfar_poll_rx_sq, GFAR_DEV_WEIGHT);
+                       netif_napi_add(dev, &priv->gfargrp[i].napi_tx,
+                                      gfar_poll_tx_sq, 2);
+               } else {
+                       netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
+                                      gfar_poll_rx, GFAR_DEV_WEIGHT);
+                       netif_napi_add(dev, &priv->gfargrp[i].napi_tx,
+                                      gfar_poll_tx, 2);
+               }
+       }
 
        if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
                dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
@@ -2146,13 +2192,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                skb_new = skb_realloc_headroom(skb, fcb_len);
                if (!skb_new) {
                        dev->stats.tx_errors++;
-                       kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        return NETDEV_TX_OK;
                }
 
                if (skb->sk)
                        skb_set_owner_w(skb_new, skb->sk);
-               consume_skb(skb);
+               dev_consume_skb_any(skb);
                skb = skb_new;
        }
 
@@ -2538,31 +2584,6 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
        netdev_tx_completed_queue(txq, howmany, bytes_sent);
 }
 
-static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&gfargrp->grplock, flags);
-       if (napi_schedule_prep(&gfargrp->napi)) {
-               gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED);
-               __napi_schedule(&gfargrp->napi);
-       } else {
-               /* Clear IEVENT, so interrupts aren't called again
-                * because of the packets that have already arrived.
-                */
-               gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK);
-       }
-       spin_unlock_irqrestore(&gfargrp->grplock, flags);
-
-}
-
-/* Interrupt Handler for Transmit complete */
-static irqreturn_t gfar_transmit(int irq, void *grp_id)
-{
-       gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id);
-       return IRQ_HANDLED;
-}
-
 static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
                           struct sk_buff *skb)
 {
@@ -2633,7 +2654,48 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
 
 irqreturn_t gfar_receive(int irq, void *grp_id)
 {
-       gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id);
+       struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
+       unsigned long flags;
+       u32 imask;
+
+       if (likely(napi_schedule_prep(&grp->napi_rx))) {
+               spin_lock_irqsave(&grp->grplock, flags);
+               imask = gfar_read(&grp->regs->imask);
+               imask &= IMASK_RX_DISABLED;
+               gfar_write(&grp->regs->imask, imask);
+               spin_unlock_irqrestore(&grp->grplock, flags);
+               __napi_schedule(&grp->napi_rx);
+       } else {
+               /* Clear IEVENT, so interrupts aren't called again
+                * because of the packets that have already arrived.
+                */
+               gfar_write(&grp->regs->ievent, IEVENT_RX_MASK);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* Interrupt Handler for Transmit complete */
+static irqreturn_t gfar_transmit(int irq, void *grp_id)
+{
+       struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
+       unsigned long flags;
+       u32 imask;
+
+       if (likely(napi_schedule_prep(&grp->napi_tx))) {
+               spin_lock_irqsave(&grp->grplock, flags);
+               imask = gfar_read(&grp->regs->imask);
+               imask &= IMASK_TX_DISABLED;
+               gfar_write(&grp->regs->imask, imask);
+               spin_unlock_irqrestore(&grp->grplock, flags);
+               __napi_schedule(&grp->napi_tx);
+       } else {
+               /* Clear IEVENT, so interrupts aren't called again
+                * because of the packets that have already arrived.
+                */
+               gfar_write(&grp->regs->ievent, IEVENT_TX_MASK);
+       }
+
        return IRQ_HANDLED;
 }
 
@@ -2757,7 +2819,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
                                rx_queue->stats.rx_bytes += pkt_len;
                                skb_record_rx_queue(skb, rx_queue->qindex);
                                gfar_process_frame(dev, skb, amount_pull,
-                                                  &rx_queue->grp->napi);
+                                                  &rx_queue->grp->napi_rx);
 
                        } else {
                                netif_warn(priv, rx_err, dev, "Missing skb!\n");
@@ -2786,55 +2848,81 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
        return howmany;
 }
 
-static int gfar_poll_sq(struct napi_struct *napi, int budget)
+static int gfar_poll_rx_sq(struct napi_struct *napi, int budget)
 {
        struct gfar_priv_grp *gfargrp =
-               container_of(napi, struct gfar_priv_grp, napi);
+               container_of(napi, struct gfar_priv_grp, napi_rx);
        struct gfar __iomem *regs = gfargrp->regs;
-       struct gfar_priv_tx_q *tx_queue = gfargrp->priv->tx_queue[0];
-       struct gfar_priv_rx_q *rx_queue = gfargrp->priv->rx_queue[0];
+       struct gfar_priv_rx_q *rx_queue = gfargrp->rx_queue;
        int work_done = 0;
 
        /* Clear IEVENT, so interrupts aren't called again
         * because of the packets that have already arrived
         */
-       gfar_write(&regs->ievent, IEVENT_RTX_MASK);
-
-       /* run Tx cleanup to completion */
-       if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx])
-               gfar_clean_tx_ring(tx_queue);
+       gfar_write(&regs->ievent, IEVENT_RX_MASK);
 
        work_done = gfar_clean_rx_ring(rx_queue, budget);
 
        if (work_done < budget) {
+               u32 imask;
                napi_complete(napi);
                /* Clear the halt bit in RSTAT */
                gfar_write(&regs->rstat, gfargrp->rstat);
 
-               gfar_write(&regs->imask, IMASK_DEFAULT);
+               spin_lock_irq(&gfargrp->grplock);
+               imask = gfar_read(&regs->imask);
+               imask |= IMASK_RX_DEFAULT;
+               gfar_write(&regs->imask, imask);
+               spin_unlock_irq(&gfargrp->grplock);
        }
 
        return work_done;
 }
 
-static int gfar_poll(struct napi_struct *napi, int budget)
+static int gfar_poll_tx_sq(struct napi_struct *napi, int budget)
+{
+       struct gfar_priv_grp *gfargrp =
+               container_of(napi, struct gfar_priv_grp, napi_tx);
+       struct gfar __iomem *regs = gfargrp->regs;
+       struct gfar_priv_tx_q *tx_queue = gfargrp->tx_queue;
+       u32 imask;
+
+       /* Clear IEVENT, so interrupts aren't called again
+        * because of the packets that have already arrived
+        */
+       gfar_write(&regs->ievent, IEVENT_TX_MASK);
+
+       /* run Tx cleanup to completion */
+       if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx])
+               gfar_clean_tx_ring(tx_queue);
+
+       napi_complete(napi);
+
+       spin_lock_irq(&gfargrp->grplock);
+       imask = gfar_read(&regs->imask);
+       imask |= IMASK_TX_DEFAULT;
+       gfar_write(&regs->imask, imask);
+       spin_unlock_irq(&gfargrp->grplock);
+
+       return 0;
+}
+
+static int gfar_poll_rx(struct napi_struct *napi, int budget)
 {
        struct gfar_priv_grp *gfargrp =
-               container_of(napi, struct gfar_priv_grp, napi);
+               container_of(napi, struct gfar_priv_grp, napi_rx);
        struct gfar_private *priv = gfargrp->priv;
        struct gfar __iomem *regs = gfargrp->regs;
-       struct gfar_priv_tx_q *tx_queue = NULL;
        struct gfar_priv_rx_q *rx_queue = NULL;
        int work_done = 0, work_done_per_q = 0;
        int i, budget_per_q = 0;
-       int has_tx_work = 0;
        unsigned long rstat_rxf;
        int num_act_queues;
 
        /* Clear IEVENT, so interrupts aren't called again
         * because of the packets that have already arrived
         */
-       gfar_write(&regs->ievent, IEVENT_RTX_MASK);
+       gfar_write(&regs->ievent, IEVENT_RX_MASK);
 
        rstat_rxf = gfar_read(&regs->rstat) & RSTAT_RXF_MASK;
 
@@ -2842,15 +2930,6 @@ static int gfar_poll(struct napi_struct *napi, int budget)
        if (num_act_queues)
                budget_per_q = budget/num_act_queues;
 
-       for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
-               tx_queue = priv->tx_queue[i];
-               /* run Tx cleanup to completion */
-               if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
-                       gfar_clean_tx_ring(tx_queue);
-                       has_tx_work = 1;
-               }
-       }
-
        for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
                /* skip queue if not active */
                if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i)))
@@ -2873,19 +2952,62 @@ static int gfar_poll(struct napi_struct *napi, int budget)
                }
        }
 
-       if (!num_act_queues && !has_tx_work) {
-
+       if (!num_act_queues) {
+               u32 imask;
                napi_complete(napi);
 
                /* Clear the halt bit in RSTAT */
                gfar_write(&regs->rstat, gfargrp->rstat);
 
-               gfar_write(&regs->imask, IMASK_DEFAULT);
+               spin_lock_irq(&gfargrp->grplock);
+               imask = gfar_read(&regs->imask);
+               imask |= IMASK_RX_DEFAULT;
+               gfar_write(&regs->imask, imask);
+               spin_unlock_irq(&gfargrp->grplock);
        }
 
        return work_done;
 }
 
+static int gfar_poll_tx(struct napi_struct *napi, int budget)
+{
+       struct gfar_priv_grp *gfargrp =
+               container_of(napi, struct gfar_priv_grp, napi_tx);
+       struct gfar_private *priv = gfargrp->priv;
+       struct gfar __iomem *regs = gfargrp->regs;
+       struct gfar_priv_tx_q *tx_queue = NULL;
+       int has_tx_work = 0;
+       int i;
+
+       /* Clear IEVENT, so interrupts aren't called again
+        * because of the packets that have already arrived
+        */
+       gfar_write(&regs->ievent, IEVENT_TX_MASK);
+
+       for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
+               tx_queue = priv->tx_queue[i];
+               /* run Tx cleanup to completion */
+               if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
+                       gfar_clean_tx_ring(tx_queue);
+                       has_tx_work = 1;
+               }
+       }
+
+       if (!has_tx_work) {
+               u32 imask;
+               napi_complete(napi);
+
+               spin_lock_irq(&gfargrp->grplock);
+               imask = gfar_read(&regs->imask);
+               imask |= IMASK_TX_DEFAULT;
+               gfar_write(&regs->imask, imask);
+               spin_unlock_irq(&gfargrp->grplock);
+       }
+
+       return 0;
+}
+
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /* Polling 'interrupt' - used by things like netconsole to send skbs
  * without having to re-enable interrupts. It's not called while
index 1e16216d4150e33a249c52ab4c66b277eb79338a..84632c569f2c3ba43225c2a9a4f773dd24ea1580 100644 (file)
@@ -377,8 +377,11 @@ extern const char gfar_driver_version[];
                IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
                IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
                | IMASK_PERR)
-#define IMASK_RTX_DISABLED ((~(IMASK_RXFEN0 | IMASK_TXFEN | IMASK_BSY)) \
-                          & IMASK_DEFAULT)
+#define IMASK_RX_DEFAULT (IMASK_RXFEN0 | IMASK_BSY)
+#define IMASK_TX_DEFAULT (IMASK_TXFEN | IMASK_TXBEN)
+
+#define IMASK_RX_DISABLED ((~(IMASK_RX_DEFAULT)) & IMASK_DEFAULT)
+#define IMASK_TX_DISABLED ((~(IMASK_TX_DEFAULT)) & IMASK_DEFAULT)
 
 /* Fifo management */
 #define FIFO_TX_THR_MASK       0x01ff
@@ -409,7 +412,9 @@ extern const char gfar_driver_version[];
 
 /* This default RIR value directly corresponds
  * to the 3-bit hash value generated */
-#define DEFAULT_RIR0   0x05397700
+#define DEFAULT_8RXQ_RIR0      0x05397700
+/* Map even hash values to Q0, and odd ones to Q1 */
+#define DEFAULT_2RXQ_RIR0      0x04104100
 
 /* RQFCR register bits */
 #define RQFCR_GPI              0x80000000
@@ -904,6 +909,22 @@ enum {
        MQ_MG_MODE
 };
 
+/* GFAR_SQ_POLLING: Single Queue NAPI polling mode
+ *     The driver supports a single pair of RX/Tx queues
+ *     per interrupt group (Rx/Tx int line). MQ_MG mode
+ *     devices have 2 interrupt groups, so the device will
+ *     have a total of 2 Tx and 2 Rx queues in this case.
+ * GFAR_MQ_POLLING: Multi Queue NAPI polling mode
+ *     The driver supports all the 8 Rx and Tx HW queues
+ *     each queue mapped by the Device Tree to one of
+ *     the 2 interrupt groups. This mode implies significant
+ *     processing overhead (CPU and controller level).
+ */
+enum gfar_poll_mode {
+       GFAR_SQ_POLLING = 0,
+       GFAR_MQ_POLLING
+};
+
 /*
  * Per TX queue stats
  */
@@ -1013,17 +1034,20 @@ struct gfar_irqinfo {
  */
 
 struct gfar_priv_grp {
-       spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES)));
-       struct  napi_struct napi;
-       struct gfar_private *priv;
+       spinlock_t grplock __aligned(SMP_CACHE_BYTES);
+       struct  napi_struct napi_rx;
+       struct  napi_struct napi_tx;
        struct gfar __iomem *regs;
-       unsigned int rstat;
-       unsigned long num_rx_queues;
-       unsigned long rx_bit_map;
-       /* cacheline 3 */
+       struct gfar_priv_tx_q *tx_queue;
+       struct gfar_priv_rx_q *rx_queue;
        unsigned int tstat;
+       unsigned int rstat;
+
+       struct gfar_private *priv;
        unsigned long num_tx_queues;
        unsigned long tx_bit_map;
+       unsigned long num_rx_queues;
+       unsigned long rx_bit_map;
 
        struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS];
 };
@@ -1053,8 +1077,6 @@ enum gfar_dev_state {
  * the buffer descriptor determines the actual condition.
  */
 struct gfar_private {
-       unsigned int num_rx_queues;
-
        struct device *dev;
        struct net_device *ndev;
        enum gfar_errata errata;
@@ -1062,6 +1084,7 @@ struct gfar_private {
 
        u16 uses_rxfcb;
        u16 padding;
+       u32 device_flags;
 
        /* HW time stamping enabled flag */
        int hwts_rx_en;
@@ -1072,10 +1095,11 @@ struct gfar_private {
        struct gfar_priv_grp gfargrp[MAXGROUPS];
 
        unsigned long state;
-       u32 device_flags;
 
-       unsigned int mode;
+       unsigned short mode;
+       unsigned short poll_mode;
        unsigned int num_tx_queues;
+       unsigned int num_rx_queues;
        unsigned int num_grps;
 
        /* Network Statistics */
index 4be9715904616b3f9c1ff2a3bc38d55b58135e58..e75bdfcd137414925ade4348722a30adc644cf8c 100644 (file)
@@ -522,10 +522,21 @@ retry:
        return rc;
 }
 
+static u64 ibmveth_encode_mac_addr(u8 *mac)
+{
+       int i;
+       u64 encoded = 0;
+
+       for (i = 0; i < ETH_ALEN; i++)
+               encoded = (encoded << 8) | mac[i];
+
+       return encoded;
+}
+
 static int ibmveth_open(struct net_device *netdev)
 {
        struct ibmveth_adapter *adapter = netdev_priv(netdev);
-       u64 mac_address = 0;
+       u64 mac_address;
        int rxq_entries = 1;
        unsigned long lpar_rc;
        int rc;
@@ -579,8 +590,7 @@ static int ibmveth_open(struct net_device *netdev)
        adapter->rx_queue.num_slots = rxq_entries;
        adapter->rx_queue.toggle = 1;
 
-       memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
-       mac_address = mac_address >> 16;
+       mac_address = ibmveth_encode_mac_addr(netdev->dev_addr);
 
        rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
                                        adapter->rx_queue.queue_len;
@@ -1062,7 +1072,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
        unsigned long lpar_rc;
 
 restart_poll:
-       do {
+       while (frames_processed < budget) {
                if (!ibmveth_rxq_pending_buffer(adapter))
                        break;
 
@@ -1111,7 +1121,7 @@ restart_poll:
                        netdev->stats.rx_bytes += length;
                        frames_processed++;
                }
-       } while (frames_processed < budget);
+       }
 
        ibmveth_replenish_task(adapter);
 
@@ -1183,8 +1193,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
                /* add the addresses to the filter table */
                netdev_for_each_mc_addr(ha, netdev) {
                        /* add the multicast address to the filter table */
-                       unsigned long mcast_addr = 0;
-                       memcpy(((char *)&mcast_addr)+2, ha->addr, ETH_ALEN);
+                       u64 mcast_addr;
+                       mcast_addr = ibmveth_encode_mac_addr(ha->addr);
                        lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
                                                   IbmVethMcastAddFilter,
                                                   mcast_addr);
@@ -1372,9 +1382,6 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
        netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
 
-       adapter->mac_addr = 0;
-       memcpy(&adapter->mac_addr, mac_addr_p, ETH_ALEN);
-
        netdev->irq = dev->irq;
        netdev->netdev_ops = &ibmveth_netdev_ops;
        netdev->ethtool_ops = &netdev_ethtool_ops;
@@ -1383,7 +1390,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        netdev->features |= netdev->hw_features;
 
-       memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
+       memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN);
 
        for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
                struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
index 451ba7949e152a66ee87e661e90722496792dfb8..1f37499d43981d260c61cdc1c089d7328a7942c9 100644 (file)
@@ -138,7 +138,6 @@ struct ibmveth_adapter {
     struct napi_struct napi;
     struct net_device_stats stats;
     unsigned int mcastFilterSize;
-    unsigned long mac_addr;
     void * buffer_list_addr;
     void * filter_list_addr;
     dma_addr_t buffer_list_dma;
index ff2d806eaef71bc2a7a861a8971c228cd6856e2a..a5f6b11d6992e63aa9af8da9f52540697455b2d1 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* 80003ES2LAN Gigabit Ethernet Controller (Copper)
  * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
index 90d363b2d2802c238cda0b1e792a21ac5afb2562..535a9430976df7653671e23d62adc1140973579e 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_80003ES2LAN_H_
 #define _E1000E_80003ES2LAN_H_
index 8fed74e3fa53da73ff781a215ac26714911a015f..e0aa7f1efb08ceb50d9049128dcbdb66f442b17d 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* 82571EB Gigabit Ethernet Controller
  * 82571EB Gigabit Ethernet Controller (Copper)
index 08e24dc3dc0e9d49c7742fed7b829826e2cea095..2e758f796d6099bc3dfb05107ea3a6ebc81dec09 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_82571_H_
 #define _E1000E_82571_H_
index c2dcfcc10857fc17608194c0a4c09140f6606143..106de493373ce6c73e85e7e2be6f6e8c3e61df0c 100644 (file)
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2013 Intel Corporation.
+# Copyright(c) 1999 - 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,
@@ -12,9 +12,8 @@
 # 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+# 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".
index 351c94a0cf74944b95c278c69709257216af64ef..d18e89212575626b880a173f08af119be2bdd20a 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000_DEFINES_H_
 #define _E1000_DEFINES_H_
 
 /* Definitions for power management and wakeup registers */
 /* Wake Up Control */
-#define E1000_WUC_APME       0x00000001 /* APM Enable */
-#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
-#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
+#define E1000_WUC_APME         0x00000001      /* APM Enable */
+#define E1000_WUC_PME_EN       0x00000002      /* PME Enable */
+#define E1000_WUC_PME_STATUS   0x00000004      /* PME Status */
+#define E1000_WUC_APMPME       0x00000008      /* Assert PME on APM Wakeup */
+#define E1000_WUC_PHY_WAKE     0x00000100      /* if PHY supports wakeup */
 
 /* Wake Up Filter Control */
 #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
index 0150f7fc893d4ae6985096f17e5a4678f39fc3b3..5325e3e2154e0929b3a56a4b3542cee52f217deb 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* Linux PRO/1000 Ethernet Driver main header file */
 
@@ -333,7 +326,6 @@ struct e1000_adapter {
        struct work_struct update_phy_task;
        struct work_struct print_hang_task;
 
-       bool idle_check;
        int phy_hang_count;
 
        u16 tx_ring_count;
@@ -476,7 +468,7 @@ void e1000e_check_options(struct e1000_adapter *adapter);
 void e1000e_set_ethtool_ops(struct net_device *netdev);
 
 int e1000e_up(struct e1000_adapter *adapter);
-void e1000e_down(struct e1000_adapter *adapter);
+void e1000e_down(struct e1000_adapter *adapter, bool reset);
 void e1000e_reinit_locked(struct e1000_adapter *adapter);
 void e1000e_reset(struct e1000_adapter *adapter);
 void e1000e_power_up_phy(struct e1000_adapter *adapter);
index d14c8f53384cd415c3933015c02bf9d2a369ba11..3c2898d0c2aa3ef0779e22e79167be37ba71e8ee 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* ethtool support for e1000 */
 
@@ -332,7 +325,7 @@ static int e1000_set_settings(struct net_device *netdev,
 
        /* reset the link */
        if (netif_running(adapter->netdev)) {
-               e1000e_down(adapter);
+               e1000e_down(adapter, true);
                e1000e_up(adapter);
        } else {
                e1000e_reset(adapter);
@@ -380,7 +373,7 @@ static int e1000_set_pauseparam(struct net_device *netdev,
        if (adapter->fc_autoneg == AUTONEG_ENABLE) {
                hw->fc.requested_mode = e1000_fc_default;
                if (netif_running(adapter->netdev)) {
-                       e1000e_down(adapter);
+                       e1000e_down(adapter, true);
                        e1000e_up(adapter);
                } else {
                        e1000e_reset(adapter);
@@ -726,7 +719,7 @@ static int e1000_set_ringparam(struct net_device *netdev,
 
        pm_runtime_get_sync(netdev->dev.parent);
 
-       e1000e_down(adapter);
+       e1000e_down(adapter, true);
 
        /* We can't just free everything and then setup again, because the
         * ISRs in MSI-X mode get passed pointers to the Tx and Rx ring
@@ -924,15 +917,21 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
                }
                if (mac->type == e1000_pch2lan) {
                        /* SHRAH[0,1,2] different than previous */
-                       if (i == 7)
+                       if (i == 1)
                                mask &= 0xFFF4FFFF;
                        /* SHRAH[3] different than SHRAH[0,1,2] */
-                       if (i == 10)
+                       if (i == 4)
                                mask |= (1 << 30);
+                       /* RAR[1-6] owned by management engine - skipping */
+                       if (i > 0)
+                               i += 6;
                }
 
                REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), mask,
                                       0xFFFFFFFF);
+               /* reset index to actual value */
+               if ((mac->type == e1000_pch2lan) && (i > 6))
+                       i -= 6;
        }
 
        for (i = 0; i < mac->mta_reg_count; i++)
index b7f38435d1fdb90336dd0c9511d78c7cd273e8d7..6b3de5f39a97862e2f5742b14a24530ba6ecc33f 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000_HW_H_
 #define _E1000_HW_H_
@@ -655,12 +648,20 @@ struct e1000_shadow_ram {
 
 #define E1000_ICH8_SHADOW_RAM_WORDS            2048
 
+/* I218 PHY Ultra Low Power (ULP) states */
+enum e1000_ulp_state {
+       e1000_ulp_state_unknown,
+       e1000_ulp_state_off,
+       e1000_ulp_state_on,
+};
+
 struct e1000_dev_spec_ich8lan {
        bool kmrn_lock_loss_workaround_enabled;
        struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
        bool nvm_k1_enabled;
        bool eee_disable;
        u16 eee_lp_ability;
+       enum e1000_ulp_state ulp_state;
 };
 
 struct e1000_hw {
index 42f0f6717511c21bb0f16edbeee050cc4878db96..9866f264f55e33a8e564757730ada0d6ab7c6a92 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* 82562G 10/100 Network Connection
  * 82562G-2 10/100 Network Connection
  * 82578DC Gigabit Network Connection
  * 82579LM Gigabit Network Connection
  * 82579V Gigabit Network Connection
+ * Ethernet Connection I217-LM
+ * Ethernet Connection I217-V
+ * Ethernet Connection I218-V
+ * Ethernet Connection I218-LM
+ * Ethernet Connection (2) I218-LM
+ * Ethernet Connection (2) I218-V
+ * Ethernet Connection (3) I218-LM
+ * Ethernet Connection (3) I218-V
  */
 
 #include "e1000.h"
@@ -142,7 +143,9 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
 static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
 static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
 static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
+static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force);
 static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
+static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state);
 
 static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
 {
@@ -238,6 +241,47 @@ out:
        return true;
 }
 
+/**
+ *  e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value
+ *  @hw: pointer to the HW structure
+ *
+ *  Toggling the LANPHYPC pin value fully power-cycles the PHY and is
+ *  used to reset the PHY to a quiescent state when necessary.
+ **/
+static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
+{
+       u32 mac_reg;
+
+       /* Set Phy Config Counter to 50msec */
+       mac_reg = er32(FEXTNVM3);
+       mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
+       mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
+       ew32(FEXTNVM3, mac_reg);
+
+       /* Toggle LANPHYPC Value bit */
+       mac_reg = er32(CTRL);
+       mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
+       mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
+       ew32(CTRL, mac_reg);
+       e1e_flush();
+       usleep_range(10, 20);
+       mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+       ew32(CTRL, mac_reg);
+       e1e_flush();
+
+       if (hw->mac.type < e1000_pch_lpt) {
+               msleep(50);
+       } else {
+               u16 count = 20;
+
+               do {
+                       usleep_range(5000, 10000);
+               } while (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LPCD) && count--);
+
+               msleep(30);
+       }
+}
+
 /**
  *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
  *  @hw: pointer to the HW structure
@@ -247,6 +291,7 @@ out:
  **/
 static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 {
+       struct e1000_adapter *adapter = hw->adapter;
        u32 mac_reg, fwsm = er32(FWSM);
        s32 ret_val;
 
@@ -255,6 +300,12 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
         */
        e1000_gate_hw_phy_config_ich8lan(hw, true);
 
+       /* It is not possible to be certain of the current state of ULP
+        * so forcibly disable it.
+        */
+       hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown;
+       e1000_disable_ulp_lpt_lp(hw, true);
+
        ret_val = hw->phy.ops.acquire(hw);
        if (ret_val) {
                e_dbg("Failed to initialize PHY flow\n");
@@ -300,33 +351,9 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
                        break;
                }
 
-               e_dbg("Toggling LANPHYPC\n");
-
-               /* Set Phy Config Counter to 50msec */
-               mac_reg = er32(FEXTNVM3);
-               mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
-               mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
-               ew32(FEXTNVM3, mac_reg);
-
                /* Toggle LANPHYPC Value bit */
-               mac_reg = er32(CTRL);
-               mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
-               mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
-               ew32(CTRL, mac_reg);
-               e1e_flush();
-               usleep_range(10, 20);
-               mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
-               ew32(CTRL, mac_reg);
-               e1e_flush();
-               if (hw->mac.type < e1000_pch_lpt) {
-                       msleep(50);
-               } else {
-                       u16 count = 20;
-                       do {
-                               usleep_range(5000, 10000);
-                       } while (!(er32(CTRL_EXT) &
-                                  E1000_CTRL_EXT_LPCD) && count--);
-                       usleep_range(30000, 60000);
+               e1000_toggle_lanphypc_pch_lpt(hw);
+               if (hw->mac.type >= e1000_pch_lpt) {
                        if (e1000_phy_is_accessible_pchlan(hw))
                                break;
 
@@ -349,12 +376,31 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 
        hw->phy.ops.release(hw);
        if (!ret_val) {
+
+               /* Check to see if able to reset PHY.  Print error if not */
+               if (hw->phy.ops.check_reset_block(hw)) {
+                       e_err("Reset blocked by ME\n");
+                       goto out;
+               }
+
                /* Reset the PHY before any access to it.  Doing so, ensures
                 * that the PHY is in a known good state before we read/write
                 * PHY registers.  The generic reset is sufficient here,
                 * because we haven't determined the PHY type yet.
                 */
                ret_val = e1000e_phy_hw_reset_generic(hw);
+               if (ret_val)
+                       goto out;
+
+               /* On a successful reset, possibly need to wait for the PHY
+                * to quiesce to an accessible state before returning control
+                * to the calling function.  If the PHY does not quiesce, then
+                * return E1000E_BLK_PHY_RESET, as this is the condition that
+                *  the PHY is in.
+                */
+               ret_val = hw->phy.ops.check_reset_block(hw);
+               if (ret_val)
+                       e_err("ME blocked access to PHY after reset\n");
        }
 
 out:
@@ -724,8 +770,14 @@ s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
  *  Enable/disable EEE based on setting in dev_spec structure, the duplex of
  *  the link and the EEE capabilities of the link partner.  The LPI Control
  *  register bits will remain set only if/when link is up.
+ *
+ *  EEE LPI must not be asserted earlier than one second after link is up.
+ *  On 82579, EEE LPI should not be enabled until such time otherwise there
+ *  can be link issues with some switches.  Other devices can have EEE LPI
+ *  enabled immediately upon link up since they have a timer in hardware which
+ *  prevents LPI from being asserted too early.
  **/
-static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
+s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
 {
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
        s32 ret_val;
@@ -978,6 +1030,253 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
        return 0;
 }
 
+/**
+ *  e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP
+ *  @hw: pointer to the HW structure
+ *  @to_sx: boolean indicating a system power state transition to Sx
+ *
+ *  When link is down, configure ULP mode to significantly reduce the power
+ *  to the PHY.  If on a Manageability Engine (ME) enabled system, tell the
+ *  ME firmware to start the ULP configuration.  If not on an ME enabled
+ *  system, configure the ULP mode by software.
+ */
+s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
+{
+       u32 mac_reg;
+       s32 ret_val = 0;
+       u16 phy_reg;
+
+       if ((hw->mac.type < e1000_pch_lpt) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) ||
+           (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on))
+               return 0;
+
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+               /* Request ME configure ULP mode in the PHY */
+               mac_reg = er32(H2ME);
+               mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS;
+               ew32(H2ME, mac_reg);
+
+               goto out;
+       }
+
+       if (!to_sx) {
+               int i = 0;
+
+               /* Poll up to 5 seconds for Cable Disconnected indication */
+               while (!(er32(FEXT) & E1000_FEXT_PHY_CABLE_DISCONNECTED)) {
+                       /* Bail if link is re-acquired */
+                       if (er32(STATUS) & E1000_STATUS_LU)
+                               return -E1000_ERR_PHY;
+
+                       if (i++ == 100)
+                               break;
+
+                       msleep(50);
+               }
+               e_dbg("CABLE_DISCONNECTED %s set after %dmsec\n",
+                     (er32(FEXT) &
+                      E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", i * 50);
+       }
+
+       ret_val = hw->phy.ops.acquire(hw);
+       if (ret_val)
+               goto out;
+
+       /* Force SMBus mode in PHY */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
+       e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
+
+       /* Force SMBus mode in MAC */
+       mac_reg = er32(CTRL_EXT);
+       mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
+       ew32(CTRL_EXT, mac_reg);
+
+       /* Set Inband ULP Exit, Reset to SMBus mode and
+        * Disable SMBus Release on PERST# in PHY
+        */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS |
+                   I218_ULP_CONFIG1_DISABLE_SMB_PERST);
+       if (to_sx) {
+               if (er32(WUFC) & E1000_WUFC_LNKC)
+                       phy_reg |= I218_ULP_CONFIG1_WOL_HOST;
+
+               phy_reg |= I218_ULP_CONFIG1_STICKY_ULP;
+       } else {
+               phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT;
+       }
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+       /* Set Disable SMBus Release on PERST# in MAC */
+       mac_reg = er32(FEXTNVM7);
+       mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST;
+       ew32(FEXTNVM7, mac_reg);
+
+       /* Commit ULP changes in PHY by starting auto ULP configuration */
+       phy_reg |= I218_ULP_CONFIG1_START;
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+release:
+       hw->phy.ops.release(hw);
+out:
+       if (ret_val)
+               e_dbg("Error in ULP enable flow: %d\n", ret_val);
+       else
+               hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on;
+
+       return ret_val;
+}
+
+/**
+ *  e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP
+ *  @hw: pointer to the HW structure
+ *  @force: boolean indicating whether or not to force disabling ULP
+ *
+ *  Un-configure ULP mode when link is up, the system is transitioned from
+ *  Sx or the driver is unloaded.  If on a Manageability Engine (ME) enabled
+ *  system, poll for an indication from ME that ULP has been un-configured.
+ *  If not on an ME enabled system, un-configure the ULP mode by software.
+ *
+ *  During nominal operation, this function is called when link is acquired
+ *  to disable ULP mode (force=false); otherwise, for example when unloading
+ *  the driver or during Sx->S0 transitions, this is called with force=true
+ *  to forcibly disable ULP.
+ */
+static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
+{
+       s32 ret_val = 0;
+       u32 mac_reg;
+       u16 phy_reg;
+       int i = 0;
+
+       if ((hw->mac.type < e1000_pch_lpt) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) ||
+           (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off))
+               return 0;
+
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+               if (force) {
+                       /* Request ME un-configure ULP mode in the PHY */
+                       mac_reg = er32(H2ME);
+                       mac_reg &= ~E1000_H2ME_ULP;
+                       mac_reg |= E1000_H2ME_ENFORCE_SETTINGS;
+                       ew32(H2ME, mac_reg);
+               }
+
+               /* Poll up to 100msec for ME to clear ULP_CFG_DONE */
+               while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) {
+                       if (i++ == 10) {
+                               ret_val = -E1000_ERR_PHY;
+                               goto out;
+                       }
+
+                       usleep_range(10000, 20000);
+               }
+               e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10);
+
+               if (force) {
+                       mac_reg = er32(H2ME);
+                       mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS;
+                       ew32(H2ME, mac_reg);
+               } else {
+                       /* Clear H2ME.ULP after ME ULP configuration */
+                       mac_reg = er32(H2ME);
+                       mac_reg &= ~E1000_H2ME_ULP;
+                       ew32(H2ME, mac_reg);
+               }
+
+               goto out;
+       }
+
+       ret_val = hw->phy.ops.acquire(hw);
+       if (ret_val)
+               goto out;
+
+       if (force)
+               /* Toggle LANPHYPC Value bit */
+               e1000_toggle_lanphypc_pch_lpt(hw);
+
+       /* Unforce SMBus mode in PHY */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
+       if (ret_val) {
+               /* The MAC might be in PCIe mode, so temporarily force to
+                * SMBus mode in order to access the PHY.
+                */
+               mac_reg = er32(CTRL_EXT);
+               mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
+               ew32(CTRL_EXT, mac_reg);
+
+               msleep(50);
+
+               ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL,
+                                                      &phy_reg);
+               if (ret_val)
+                       goto release;
+       }
+       phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
+       e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
+
+       /* Unforce SMBus mode in MAC */
+       mac_reg = er32(CTRL_EXT);
+       mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+       ew32(CTRL_EXT, mac_reg);
+
+       /* When ULP mode was previously entered, K1 was disabled by the
+        * hardware.  Re-Enable K1 in the PHY when exiting ULP.
+        */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg |= HV_PM_CTRL_K1_ENABLE;
+       e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg);
+
+       /* Clear ULP enabled configuration */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg &= ~(I218_ULP_CONFIG1_IND |
+                    I218_ULP_CONFIG1_STICKY_ULP |
+                    I218_ULP_CONFIG1_RESET_TO_SMBUS |
+                    I218_ULP_CONFIG1_WOL_HOST |
+                    I218_ULP_CONFIG1_INBAND_EXIT |
+                    I218_ULP_CONFIG1_DISABLE_SMB_PERST);
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+       /* Commit ULP changes by starting auto ULP configuration */
+       phy_reg |= I218_ULP_CONFIG1_START;
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+       /* Clear Disable SMBus Release on PERST# in MAC */
+       mac_reg = er32(FEXTNVM7);
+       mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST;
+       ew32(FEXTNVM7, mac_reg);
+
+release:
+       hw->phy.ops.release(hw);
+       if (force) {
+               e1000_phy_hw_reset(hw);
+               msleep(50);
+       }
+out:
+       if (ret_val)
+               e_dbg("Error in ULP disable flow: %d\n", ret_val);
+       else
+               hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off;
+
+       return ret_val;
+}
+
 /**
  *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
  *  @hw: pointer to the HW structure
@@ -1106,9 +1405,11 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
        e1000e_check_downshift(hw);
 
        /* Enable/Disable EEE after link up */
-       ret_val = e1000_set_eee_pchlan(hw);
-       if (ret_val)
-               return ret_val;
+       if (hw->phy.type > e1000_phy_82579) {
+               ret_val = e1000_set_eee_pchlan(hw);
+               if (ret_val)
+                       return ret_val;
+       }
 
        /* If we are forcing speed/duplex, then we simply return since
         * we have already determined whether we have link or not.
@@ -1374,7 +1675,7 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
        /* RAR[1-6] are owned by manageability.  Skip those and program the
         * next address into the SHRA register array.
         */
-       if (index < (u32)(hw->mac.rar_entry_count - 6)) {
+       if (index < (u32)(hw->mac.rar_entry_count)) {
                s32 ret_val;
 
                ret_val = e1000_acquire_swflag_ich8lan(hw);
@@ -1484,11 +1785,13 @@ out:
  **/
 static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
 {
-       u32 fwsm;
+       bool blocked = false;
+       int i = 0;
 
-       fwsm = er32(FWSM);
-
-       return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET;
+       while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) &&
+              (i++ < 10))
+               usleep_range(10000, 20000);
+       return blocked ? E1000_BLK_PHY_RESET : 0;
 }
 
 /**
index 217090df33e788d46603f1c0369a2cf4e8041719..bead50f9187b527291596da67351339b64482707 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_ICH8LAN_H_
 #define _E1000E_ICH8LAN_H_
 
 #define E1000_FWSM_WLOCK_MAC_MASK      0x0380
 #define E1000_FWSM_WLOCK_MAC_SHIFT     7
+#define E1000_FWSM_ULP_CFG_DONE                0x00000400      /* Low power cfg done */
 
 /* Shared Receive Address Registers */
 #define E1000_SHRAL_PCH_LPT(_i)                (0x05408 + ((_i) * 8))
 #define E1000_SHRAH_PCH_LPT(_i)                (0x0540C + ((_i) * 8))
 
+#define E1000_H2ME             0x05B50 /* Host to ME */
+#define E1000_H2ME_ULP         0x00000800      /* ULP Indication Bit */
+#define E1000_H2ME_ENFORCE_SETTINGS    0x00001000      /* Enforce Settings */
+
 #define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
                                 (ID_LED_OFF1_OFF2 <<  8) | \
                                 (ID_LED_OFF1_ON2  <<  4) | \
@@ -82,6 +80,9 @@
 
 #define E1000_ICH8_LAN_INIT_TIMEOUT    1500
 
+/* FEXT register bit definition */
+#define E1000_FEXT_PHY_CABLE_DISCONNECTED      0x00000004
+
 #define E1000_FEXTNVM_SW_CONFIG                1
 #define E1000_FEXTNVM_SW_CONFIG_ICH8M  (1 << 27)       /* different on ICH8M */
 
 #define E1000_FEXTNVM6_REQ_PLL_CLK     0x00000100
 #define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION       0x00000200
 
+#define E1000_FEXTNVM7_DISABLE_SMB_PERST       0x00000020
+
 #define PCIE_ICH8_SNOOP_ALL    PCIE_NO_SNOOP_ALL
 
 #define E1000_ICH_RAR_ENTRIES  7
-#define E1000_PCH2_RAR_ENTRIES 11      /* RAR[0-6], SHRA[0-3] */
+#define E1000_PCH2_RAR_ENTRIES 5       /* RAR[0], SHRA[0-3] */
 #define E1000_PCH_LPT_RAR_ENTRIES      12      /* RAR[0], SHRA[0-10] */
 
 #define PHY_PAGE_SHIFT         5
 #define CV_SMB_CTRL            PHY_REG(769, 23)
 #define CV_SMB_CTRL_FORCE_SMBUS        0x0001
 
+/* I218 Ultra Low Power Configuration 1 Register */
+#define I218_ULP_CONFIG1               PHY_REG(779, 16)
+#define I218_ULP_CONFIG1_START         0x0001  /* Start auto ULP config */
+#define I218_ULP_CONFIG1_IND           0x0004  /* Pwr up from ULP indication */
+#define I218_ULP_CONFIG1_STICKY_ULP    0x0010  /* Set sticky ULP mode */
+#define I218_ULP_CONFIG1_INBAND_EXIT   0x0020  /* Inband on ULP exit */
+#define I218_ULP_CONFIG1_WOL_HOST      0x0040  /* WoL Host on ULP exit */
+#define I218_ULP_CONFIG1_RESET_TO_SMBUS        0x0100  /* Reset to SMBus mode */
+#define I218_ULP_CONFIG1_DISABLE_SMB_PERST     0x1000  /* Disable on PERST# */
+
 /* SMBus Address Phy Register */
 #define HV_SMB_ADDR            PHY_REG(768, 26)
 #define HV_SMB_ADDR_MASK       0x007F
 /* PHY Power Management Control */
 #define HV_PM_CTRL             PHY_REG(770, 17)
 #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
+#define HV_PM_CTRL_K1_ENABLE           0x4000
 
 #define SW_FLAG_TIMEOUT                1000    /* SW Semaphore flag timeout in ms */
 
@@ -268,4 +282,6 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
 s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
 s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
 s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data);
+s32 e1000_set_eee_pchlan(struct e1000_hw *hw);
+s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx);
 #endif /* _E1000E_ICH8LAN_H_ */
index 2480c1091873864991d9342b6ce15df61b07c000..baa0a466d1d05ca533999b9ffcac3846a476ab5f 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include "e1000.h"
 
index a61fee404ebeddf31b8ad636582fb740552e2c7c..4e81c2825b7a1ca60b9a870ce61737e29d4e7972 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_MAC_H_
 #define _E1000E_MAC_H_
index e4b0f1ef92f6fdcc95b193910c7a7947e0063dbd..cb37ff1f1321991c34f17b80d820e9d923d0d3aa 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include "e1000.h"
 
index 326897c29ea81e5f319e2cad932f6870a8e69fe9..a8c27f98f7b05e15d9548ba78df62c1c351ac91d 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_MANAGE_H_
 #define _E1000E_MANAGE_H_
index e6f8961d49ebe4dbe2e998d8e90bbee61e87f04c..eafad410e59a798fb127f6026a5bcd1722081c48 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
@@ -885,7 +878,7 @@ static inline void e1000_rx_hash(struct net_device *netdev, __le32 rss,
                                 struct sk_buff *skb)
 {
        if (netdev->features & NETIF_F_RXHASH)
-               skb->rxhash = le32_to_cpu(rss);
+               skb_set_hash(skb, le32_to_cpu(rss), PKT_HASH_TYPE_L3);
 }
 
 /**
@@ -1701,7 +1694,7 @@ static void e1000_clean_rx_ring(struct e1000_ring *rx_ring)
        adapter->flags2 &= ~FLAG2_IS_DISCARDING;
 
        writel(0, rx_ring->head);
-       if (rx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+       if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
                e1000e_update_rdt_wa(rx_ring, 0);
        else
                writel(0, rx_ring->tail);
@@ -2405,7 +2398,7 @@ static void e1000_clean_tx_ring(struct e1000_ring *tx_ring)
        tx_ring->next_to_clean = 0;
 
        writel(0, tx_ring->head);
-       if (tx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+       if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
                e1000e_update_tdt_wa(tx_ring, 0);
        else
                writel(0, tx_ring->tail);
@@ -3334,6 +3327,9 @@ static void e1000e_set_rx_mode(struct net_device *netdev)
        struct e1000_hw *hw = &adapter->hw;
        u32 rctl;
 
+       if (pm_runtime_suspended(netdev->dev.parent))
+               return;
+
        /* Check for Promiscuous and All Multicast modes */
        rctl = er32(RCTL);
 
@@ -3694,10 +3690,6 @@ void e1000e_power_up_phy(struct e1000_adapter *adapter)
  */
 static void e1000_power_down_phy(struct e1000_adapter *adapter)
 {
-       /* WoL is enabled */
-       if (adapter->wol)
-               return;
-
        if (adapter->hw.phy.ops.power_down)
                adapter->hw.phy.ops.power_down(&adapter->hw);
 }
@@ -3914,10 +3906,8 @@ void e1000e_reset(struct e1000_adapter *adapter)
        }
 
        if (!netif_running(adapter->netdev) &&
-           !test_bit(__E1000_TESTING, &adapter->state)) {
+           !test_bit(__E1000_TESTING, &adapter->state))
                e1000_power_down_phy(adapter);
-               return;
-       }
 
        e1000_get_phy_info(hw);
 
@@ -3984,7 +3974,12 @@ static void e1000e_flush_descriptors(struct e1000_adapter *adapter)
 
 static void e1000e_update_stats(struct e1000_adapter *adapter);
 
-void e1000e_down(struct e1000_adapter *adapter)
+/**
+ * e1000e_down - quiesce the device and optionally reset the hardware
+ * @adapter: board private structure
+ * @reset: boolean flag to reset the hardware or not
+ */
+void e1000e_down(struct e1000_adapter *adapter, bool reset)
 {
        struct net_device *netdev = adapter->netdev;
        struct e1000_hw *hw = &adapter->hw;
@@ -4038,12 +4033,8 @@ void e1000e_down(struct e1000_adapter *adapter)
            e1000_lv_jumbo_workaround_ich8lan(hw, false))
                e_dbg("failed to disable jumbo frame workaround mode\n");
 
-       if (!pci_channel_offline(adapter->pdev))
+       if (reset && !pci_channel_offline(adapter->pdev))
                e1000e_reset(adapter);
-
-       /* TODO: for power management, we could drop the link and
-        * pci_disable_device here.
-        */
 }
 
 void e1000e_reinit_locked(struct e1000_adapter *adapter)
@@ -4051,7 +4042,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter)
        might_sleep();
        while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
                usleep_range(1000, 2000);
-       e1000e_down(adapter);
+       e1000e_down(adapter, true);
        e1000e_up(adapter);
        clear_bit(__E1000_RESETTING, &adapter->state);
 }
@@ -4329,7 +4320,6 @@ static int e1000_open(struct net_device *netdev)
        adapter->tx_hang_recheck = false;
        netif_start_queue(netdev);
 
-       adapter->idle_check = true;
        hw->mac.get_link_status = true;
        pm_runtime_put(&pdev->dev);
 
@@ -4379,14 +4369,15 @@ static int e1000_close(struct net_device *netdev)
        pm_runtime_get_sync(&pdev->dev);
 
        if (!test_bit(__E1000_DOWN, &adapter->state)) {
-               e1000e_down(adapter);
+               e1000e_down(adapter, true);
                e1000_free_irq(adapter);
+
+               /* Link status message must follow this format */
+               pr_info("%s NIC Link is Down\n", adapter->netdev->name);
        }
 
        napi_disable(&adapter->napi);
 
-       e1000_power_down_phy(adapter);
-
        e1000e_free_tx_resources(adapter->tx_ring);
        e1000e_free_rx_resources(adapter->rx_ring);
 
@@ -4463,11 +4454,16 @@ static void e1000e_update_phy_task(struct work_struct *work)
        struct e1000_adapter *adapter = container_of(work,
                                                     struct e1000_adapter,
                                                     update_phy_task);
+       struct e1000_hw *hw = &adapter->hw;
 
        if (test_bit(__E1000_DOWN, &adapter->state))
                return;
 
-       e1000_get_phy_info(&adapter->hw);
+       e1000_get_phy_info(hw);
+
+       /* Enable EEE on 82579 after link up */
+       if (hw->phy.type == e1000_phy_82579)
+               e1000_set_eee_pchlan(hw);
 }
 
 /**
@@ -5687,8 +5683,11 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        adapter->max_frame_size = max_frame;
        e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu);
        netdev->mtu = new_mtu;
+
+       pm_runtime_get_sync(netdev->dev.parent);
+
        if (netif_running(netdev))
-               e1000e_down(adapter);
+               e1000e_down(adapter, true);
 
        /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
         * means we reserve 2 more, this pushes us to allocate from the next
@@ -5714,6 +5713,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        else
                e1000e_reset(adapter);
 
+       pm_runtime_put_sync(netdev->dev.parent);
+
        clear_bit(__E1000_RESETTING, &adapter->state);
 
        return 0;
@@ -5855,7 +5856,7 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
 {
        struct e1000_hw *hw = &adapter->hw;
-       u32 i, mac_reg;
+       u32 i, mac_reg, wuc;
        u16 phy_reg, wuc_enable;
        int retval;
 
@@ -5902,13 +5903,18 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
                phy_reg |= BM_RCTL_RFCE;
        hw->phy.ops.write_reg_page(&adapter->hw, BM_RCTL, phy_reg);
 
+       wuc = E1000_WUC_PME_EN;
+       if (wufc & (E1000_WUFC_MAG | E1000_WUFC_LNKC))
+               wuc |= E1000_WUC_APME;
+
        /* enable PHY wakeup in MAC register */
        ew32(WUFC, wufc);
-       ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN);
+       ew32(WUC, (E1000_WUC_PHY_WAKE | E1000_WUC_APMPME |
+                  E1000_WUC_PME_STATUS | wuc));
 
        /* configure and enable PHY wakeup in PHY registers */
        hw->phy.ops.write_reg_page(&adapter->hw, BM_WUFC, wufc);
-       hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, E1000_WUC_PME_EN);
+       hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, wuc);
 
        /* activate PHY wakeup */
        wuc_enable |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT;
@@ -5921,15 +5927,10 @@ release:
        return retval;
 }
 
-static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+static int e1000e_pm_freeze(struct device *dev)
 {
-       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       struct e1000_hw *hw = &adapter->hw;
-       u32 ctrl, ctrl_ext, rctl, status;
-       /* Runtime suspend should only enable wakeup for link changes */
-       u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
-       int retval = 0;
 
        netif_device_detach(netdev);
 
@@ -5940,11 +5941,29 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
                        usleep_range(10000, 20000);
 
                WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
-               e1000e_down(adapter);
+
+               /* Quiesce the device without resetting the hardware */
+               e1000e_down(adapter, false);
                e1000_free_irq(adapter);
        }
        e1000e_reset_interrupt_capability(adapter);
 
+       /* Allow time for pending master requests to run */
+       e1000e_disable_pcie_master(&adapter->hw);
+
+       return 0;
+}
+
+static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 ctrl, ctrl_ext, rctl, status;
+       /* Runtime suspend should only enable wakeup for link changes */
+       u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
+       int retval = 0;
+
        status = er32(STATUS);
        if (status & E1000_STATUS_LU)
                wufc &= ~E1000_WUFC_LNKC;
@@ -5975,12 +5994,12 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
                        ew32(CTRL_EXT, ctrl_ext);
                }
 
+               if (!runtime)
+                       e1000e_power_up_phy(adapter);
+
                if (adapter->flags & FLAG_IS_ICH)
                        e1000_suspend_workarounds_ich8lan(&adapter->hw);
 
-               /* Allow time for pending master requests to run */
-               e1000e_disable_pcie_master(&adapter->hw);
-
                if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) {
                        /* enable wakeup by the PHY */
                        retval = e1000_init_phy_wakeup(adapter, wufc);
@@ -5994,10 +6013,23 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
        } else {
                ew32(WUC, 0);
                ew32(WUFC, 0);
+
+               e1000_power_down_phy(adapter);
        }
 
-       if (adapter->hw.phy.type == e1000_phy_igp_3)
+       if (adapter->hw.phy.type == e1000_phy_igp_3) {
                e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
+       } else if (hw->mac.type == e1000_pch_lpt) {
+               if (!(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC)))
+                       /* ULP does not support wake from unicast, multicast
+                        * or broadcast.
+                        */
+                       retval = e1000_enable_ulp_lpt_lp(hw, !runtime);
+
+               if (retval)
+                       return retval;
+       }
+
 
        /* Release control of h/w to f/w.  If f/w is AMT enabled, this
         * would have already happened in close and is redundant.
@@ -6105,18 +6137,12 @@ static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
 }
 
 #ifdef CONFIG_PM
-static bool e1000e_pm_ready(struct e1000_adapter *adapter)
-{
-       return !!adapter->tx_ring->buffer_info;
-}
-
 static int __e1000_resume(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        u16 aspm_disable_flag = 0;
-       u32 err;
 
        if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S)
                aspm_disable_flag = PCIE_LINK_STATE_L0S;
@@ -6127,13 +6153,6 @@ static int __e1000_resume(struct pci_dev *pdev)
 
        pci_set_master(pdev);
 
-       e1000e_set_interrupt_capability(adapter);
-       if (netif_running(netdev)) {
-               err = e1000_request_irq(adapter);
-               if (err)
-                       return err;
-       }
-
        if (hw->mac.type >= e1000_pch2lan)
                e1000_resume_workarounds_pchlan(&adapter->hw);
 
@@ -6172,11 +6191,6 @@ static int __e1000_resume(struct pci_dev *pdev)
 
        e1000_init_manageability_pt(adapter);
 
-       if (netif_running(netdev))
-               e1000e_up(adapter);
-
-       netif_device_attach(netdev);
-
        /* If the controller has AMT, do not set DRV_LOAD until the interface
         * is up.  For all other cases, let the f/w know that the h/w is now
         * under the control of the driver.
@@ -6187,75 +6201,111 @@ static int __e1000_resume(struct pci_dev *pdev)
        return 0;
 }
 
+static int e1000e_pm_thaw(struct device *dev)
+{
+       struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       e1000e_set_interrupt_capability(adapter);
+       if (netif_running(netdev)) {
+               u32 err = e1000_request_irq(adapter);
+
+               if (err)
+                       return err;
+
+               e1000e_up(adapter);
+       }
+
+       netif_device_attach(netdev);
+
+       return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
-static int e1000_suspend(struct device *dev)
+static int e1000e_pm_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
 
+       e1000e_pm_freeze(dev);
+
        return __e1000_shutdown(pdev, false);
 }
 
-static int e1000_resume(struct device *dev)
+static int e1000e_pm_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct net_device *netdev = pci_get_drvdata(pdev);
-       struct e1000_adapter *adapter = netdev_priv(netdev);
+       int rc;
 
-       if (e1000e_pm_ready(adapter))
-               adapter->idle_check = true;
+       rc = __e1000_resume(pdev);
+       if (rc)
+               return rc;
 
-       return __e1000_resume(pdev);
+       return e1000e_pm_thaw(dev);
 }
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_RUNTIME
-static int e1000_runtime_suspend(struct device *dev)
+static int e1000e_pm_runtime_idle(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
 
-       if (!e1000e_pm_ready(adapter))
-               return 0;
+       if (!e1000e_has_link(adapter))
+               pm_schedule_suspend(dev, 5 * MSEC_PER_SEC);
 
-       return __e1000_shutdown(pdev, true);
+       return -EBUSY;
 }
 
-static int e1000_idle(struct device *dev)
+static int e1000e_pm_runtime_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
+       int rc;
 
-       if (!e1000e_pm_ready(adapter))
-               return 0;
+       rc = __e1000_resume(pdev);
+       if (rc)
+               return rc;
 
-       if (adapter->idle_check) {
-               adapter->idle_check = false;
-               if (!e1000e_has_link(adapter))
-                       pm_schedule_suspend(dev, MSEC_PER_SEC);
-       }
+       if (netdev->flags & IFF_UP)
+               rc = e1000e_up(adapter);
 
-       return -EBUSY;
+       return rc;
 }
 
-static int e1000_runtime_resume(struct device *dev)
+static int e1000e_pm_runtime_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
 
-       if (!e1000e_pm_ready(adapter))
-               return 0;
+       if (netdev->flags & IFF_UP) {
+               int count = E1000_CHECK_RESET_COUNT;
 
-       adapter->idle_check = !dev->power.runtime_auto;
-       return __e1000_resume(pdev);
+               while (test_bit(__E1000_RESETTING, &adapter->state) && count--)
+                       usleep_range(10000, 20000);
+
+               WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
+
+               /* Down the device without resetting the hardware */
+               e1000e_down(adapter, false);
+       }
+
+       if (__e1000_shutdown(pdev, true)) {
+               e1000e_pm_runtime_resume(dev);
+               return -EBUSY;
+       }
+
+       return 0;
 }
 #endif /* CONFIG_PM_RUNTIME */
 #endif /* CONFIG_PM */
 
 static void e1000_shutdown(struct pci_dev *pdev)
 {
+       e1000e_pm_freeze(&pdev->dev);
+
        __e1000_shutdown(pdev, false);
 }
 
@@ -6341,7 +6391,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
                return PCI_ERS_RESULT_DISCONNECT;
 
        if (netif_running(netdev))
-               e1000e_down(adapter);
+               e1000e_down(adapter, true);
        pci_disable_device(pdev);
 
        /* Request a slot slot reset. */
@@ -6353,7 +6403,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
  * @pdev: Pointer to PCI device
  *
  * Restart the card from scratch, as if from a cold-boot. Implementation
- * resembles the first-half of the e1000_resume routine.
+ * resembles the first-half of the e1000e_pm_resume routine.
  */
 static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
 {
@@ -6400,7 +6450,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
  *
  * This callback is called when the error recovery driver tells us that
  * its OK to resume normal operation. Implementation resembles the
- * second-half of the e1000_resume routine.
+ * second-half of the e1000e_pm_resume routine.
  */
 static void e1000_io_resume(struct pci_dev *pdev)
 {
@@ -6905,9 +6955,6 @@ static void e1000_remove(struct pci_dev *pdev)
                }
        }
 
-       if (!(netdev->flags & IFF_UP))
-               e1000_power_down_phy(adapter);
-
        /* Don't lie to e1000_close() down the road. */
        if (!down)
                clear_bit(__E1000_DOWN, &adapter->state);
@@ -7029,9 +7076,16 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
 MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
 
 static const struct dev_pm_ops e1000_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume)
-       SET_RUNTIME_PM_OPS(e1000_runtime_suspend, e1000_runtime_resume,
-                          e1000_idle)
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = e1000e_pm_suspend,
+       .resume         = e1000e_pm_resume,
+       .freeze         = e1000e_pm_freeze,
+       .thaw           = e1000e_pm_thaw,
+       .poweroff       = e1000e_pm_suspend,
+       .restore        = e1000e_pm_resume,
+#endif
+       SET_RUNTIME_PM_OPS(e1000e_pm_runtime_suspend, e1000e_pm_runtime_resume,
+                          e1000e_pm_runtime_idle)
 };
 
 /* PCI Device API Driver */
@@ -7058,7 +7112,7 @@ static int __init e1000_init_module(void)
        int ret;
        pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
                e1000e_driver_version);
-       pr_info("Copyright(c) 1999 - 2013 Intel Corporation.\n");
+       pr_info("Copyright(c) 1999 - 2014 Intel Corporation.\n");
        ret = pci_register_driver(&e1000_driver);
 
        return ret;
index d70a03906ac0a0cecfb3f078fa584e376eae061a..a9a976f04bffe957e22b0852bd8918c6d6f63bd0 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include "e1000.h"
 
index 45fc69561627d87b9d59dcbfb3a74b34f48e175d..342bf69efab545efcd460eaeb3d50198a22af408 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_NVM_H_
 #define _E1000E_NVM_H_
index c16bd75b6caa3f85f4f510da7fb56bafcd0f2b40..d0ac0f3249c886415d308c4a0cd376feda3d44db 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include <linux/netdevice.h>
 #include <linux/module.h>
@@ -381,6 +374,12 @@ void e1000e_check_options(struct e1000_adapter *adapter)
                                 "%s set to dynamic mode\n", opt.name);
                        adapter->itr = 20000;
                        break;
+               case 2:
+                       dev_info(&adapter->pdev->dev,
+                                "%s Invalid mode - setting default\n",
+                                opt.name);
+                       adapter->itr_setting = opt.def;
+                       /* fall-through */
                case 3:
                        dev_info(&adapter->pdev->dev,
                                 "%s set to dynamic conservative mode\n",
index 20e71f4ca4261f99694b04eccd3647906326239d..00b3fc98bf309bf3d371a984f0da7245caf07013 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include "e1000.h"
 
index f4f71b9991e3733bc35d7b17381e4cae04a28113..3841bccf058c7aa0fe3b2f90e2c70c38e9b6f209 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_PHY_H_
 #define _E1000E_PHY_H_
index 065f8c80d4f2d751e2cd2763f3bd6d1e73b6ab9b..3bd79a3ff8295f306ebdd22ffee782de858389a5 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* PTP 1588 Hardware Clock (PHC)
  * Derived from PTP Hardware Clock driver for Intel 82576 and 82580 (igb)
@@ -47,6 +40,7 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
                                                     ptp_clock_info);
        struct e1000_hw *hw = &adapter->hw;
        bool neg_adj = false;
+       unsigned long flags;
        u64 adjustment;
        u32 timinca, incvalue;
        s32 ret_val;
@@ -64,6 +58,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
        if (ret_val)
                return ret_val;
 
+       spin_lock_irqsave(&adapter->systim_lock, flags);
+
        incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
 
        adjustment = incvalue;
@@ -77,6 +73,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
 
        ew32(TIMINCA, timinca);
 
+       spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
        return 0;
 }
 
index a7e6a3e37257b34f200ba01c3525fd3269964943..ea235bbe50d3c3d32361f505cd98ddfcec5d9744 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_REGS_H_
 #define _E1000E_REGS_H_
@@ -39,6 +32,7 @@
 #define E1000_SCTL     0x00024 /* SerDes Control - RW */
 #define E1000_FCAL     0x00028 /* Flow Control Address Low - RW */
 #define E1000_FCAH     0x0002C /* Flow Control Address High -RW */
+#define E1000_FEXT     0x0002C /* Future Extended - RW */
 #define E1000_FEXTNVM  0x00028 /* Future Extended NVM - RW */
 #define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */
 #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
index 72dae4d97b43e37690fe74818b818d3a9a1e14dc..bd1b4690a6089436e79031126d2f362a52850883 100644 (file)
 
 #define I40E_NVM_VERSION_LO_SHIFT  0
 #define I40E_NVM_VERSION_LO_MASK   (0xff << I40E_NVM_VERSION_LO_SHIFT)
-#define I40E_NVM_VERSION_HI_SHIFT  8
-#define I40E_NVM_VERSION_HI_MASK   (0xff << I40E_NVM_VERSION_HI_SHIFT)
+#define I40E_NVM_VERSION_HI_SHIFT  12
+#define I40E_NVM_VERSION_HI_MASK   (0xf << I40E_NVM_VERSION_HI_SHIFT)
 
 /* 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 0x30
+#define I40E_CURRENT_NVM_VERSION_LO 0x40
 
 /* magic for getting defines into strings */
 #define STRINGIFY(foo)  #foo
@@ -152,8 +152,21 @@ struct i40e_lump_tracking {
 };
 
 #define I40E_DEFAULT_ATR_SAMPLE_RATE   20
-#define I40E_FDIR_MAX_RAW_PACKET_LOOKUP 512
-struct i40e_fdir_data {
+#define I40E_FDIR_MAX_RAW_PACKET_SIZE  512
+#define I40E_FDIR_BUFFER_FULL_MARGIN   10
+#define I40E_FDIR_BUFFER_HEAD_ROOM     200
+
+struct i40e_fdir_filter {
+       struct hlist_node fdir_node;
+       /* filter ipnut set */
+       u8 flow_type;
+       u8 ip4_proto;
+       __be32 dst_ip[4];
+       __be32 src_ip[4];
+       __be16 src_port;
+       __be16 dst_port;
+       __be32 sctp_v_tag;
+       /* filter control */
        u16 q_index;
        u8  flex_off;
        u8  pctype;
@@ -162,7 +175,6 @@ struct i40e_fdir_data {
        u8  fd_status;
        u16 cnt_index;
        u32 fd_id;
-       u8  *raw_packet;
 };
 
 #define I40E_ETH_P_LLDP                        0x88cc
@@ -210,6 +222,9 @@ struct i40e_pf {
        u8 atr_sample_rate;
        bool wol_en;
 
+       struct hlist_head fdir_filter_list;
+       u16 fdir_pf_active_filters;
+
 #ifdef CONFIG_I40E_VXLAN
        __be16  vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
        u16 pending_vxlan_bitmap;
@@ -251,6 +266,9 @@ struct i40e_pf {
 #define I40E_FLAG_VXLAN_FILTER_SYNC            (u64)(1 << 27)
 #endif
 
+       /* tracks features that get auto disabled by errors */
+       u64 auto_disable_flags;
+
        bool stat_offsets_loaded;
        struct i40e_hw_port_stats stats;
        struct i40e_hw_port_stats stats_offsets;
@@ -477,10 +495,10 @@ static inline char *i40e_fw_version_str(struct i40e_hw *hw)
                 "f%d.%d a%d.%d n%02x.%02x e%08x",
                 hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
                 hw->aq.api_maj_ver, hw->aq.api_min_ver,
-                (hw->nvm.version & I40E_NVM_VERSION_HI_MASK)
-                                               >> I40E_NVM_VERSION_HI_SHIFT,
-                (hw->nvm.version & I40E_NVM_VERSION_LO_MASK)
-                                               >> I40E_NVM_VERSION_LO_SHIFT,
+                (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) >>
+                       I40E_NVM_VERSION_HI_SHIFT,
+                (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) >>
+                       I40E_NVM_VERSION_LO_SHIFT,
                 hw->nvm.eetrack);
 
        return buf;
@@ -534,9 +552,12 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi);
 int i40e_fetch_switch_configuration(struct i40e_pf *pf,
                                    bool printconfig);
 
-int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
+int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
                             struct i40e_pf *pf, bool add);
-
+int i40e_add_del_fdir(struct i40e_vsi *vsi,
+                     struct i40e_fdir_filter *input, bool add);
+void i40e_fdir_check_and_reenable(struct i40e_pf *pf);
+int i40e_get_current_fd_count(struct i40e_pf *pf);
 void i40e_set_ethtool_ops(struct net_device *netdev);
 struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
                                        u8 *macaddr, s16 vlan,
index e7f38b57834d978a82c541df8bb26ffc3ce46937..bb948dd924743f2305491a4836897116bdbaac30 100644 (file)
@@ -162,6 +162,372 @@ i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw,
        return status;
 }
 
+/* The i40e_ptype_lookup table is used to convert from the 8-bit ptype in the
+ * hardware to a bit-field that can be used by SW to more easily determine the
+ * packet type.
+ *
+ * Macros are used to shorten the table lines and make this table human
+ * readable.
+ *
+ * We store the PTYPE in the top byte of the bit field - this is just so that
+ * we can check that the table doesn't have a row missing, as the index into
+ * the table should be the PTYPE.
+ *
+ * Typical work flow:
+ *
+ * IF NOT i40e_ptype_lookup[ptype].known
+ * THEN
+ *      Packet is unknown
+ * ELSE IF i40e_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP
+ *      Use the rest of the fields to look at the tunnels, inner protocols, etc
+ * ELSE
+ *      Use the enum i40e_rx_l2_ptype to decode the packet type
+ * ENDIF
+ */
+
+/* macro to make the table lines short */
+#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
+       {       PTYPE, \
+               1, \
+               I40E_RX_PTYPE_OUTER_##OUTER_IP, \
+               I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \
+               I40E_RX_PTYPE_##OUTER_FRAG, \
+               I40E_RX_PTYPE_TUNNEL_##T, \
+               I40E_RX_PTYPE_TUNNEL_END_##TE, \
+               I40E_RX_PTYPE_##TEF, \
+               I40E_RX_PTYPE_INNER_PROT_##I, \
+               I40E_RX_PTYPE_PAYLOAD_LAYER_##PL }
+
+#define I40E_PTT_UNUSED_ENTRY(PTYPE) \
+               { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+
+/* shorter macros makes the table fit but are terse */
+#define I40E_RX_PTYPE_NOF              I40E_RX_PTYPE_NOT_FRAG
+#define I40E_RX_PTYPE_FRG              I40E_RX_PTYPE_FRAG
+#define I40E_RX_PTYPE_INNER_PROT_TS    I40E_RX_PTYPE_INNER_PROT_TIMESYNC
+
+/* Lookup table mapping the HW PTYPE to the bit field for decoding */
+struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = {
+       /* L2 Packet types */
+       I40E_PTT_UNUSED_ENTRY(0),
+       I40E_PTT(1,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(2,  L2, NONE, NOF, NONE, NONE, NOF, TS,   PAY2),
+       I40E_PTT(3,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT_UNUSED_ENTRY(4),
+       I40E_PTT_UNUSED_ENTRY(5),
+       I40E_PTT(6,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(7,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT_UNUSED_ENTRY(8),
+       I40E_PTT_UNUSED_ENTRY(9),
+       I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
+       I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+
+       /* Non Tunneled IPv4 */
+       I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(25),
+       I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP,  PAY4),
+       I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4),
+       I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+       /* IPv4 --> IPv4 */
+       I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(32),
+       I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> IPv6 */
+       I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(39),
+       I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT */
+       I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 --> GRE/NAT --> IPv4 */
+       I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(47),
+       I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> IPv6 */
+       I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(54),
+       I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> MAC */
+       I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 --> GRE/NAT --> MAC --> IPv4 */
+       I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(62),
+       I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT -> MAC --> IPv6 */
+       I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(69),
+       I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> MAC/VLAN */
+       I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */
+       I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(77),
+       I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */
+       I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(84),
+       I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+       /* Non Tunneled IPv6 */
+       I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP,  PAY3),
+       I40E_PTT_UNUSED_ENTRY(91),
+       I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP,  PAY4),
+       I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
+       I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+       /* IPv6 --> IPv4 */
+       I40E_PTT(95,  IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(96,  IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(97,  IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(98),
+       I40E_PTT(99,  IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> IPv6 */
+       I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(105),
+       I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT */
+       I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> IPv4 */
+       I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(113),
+       I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> IPv6 */
+       I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(120),
+       I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC */
+       I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> MAC -> IPv4 */
+       I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(128),
+       I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC -> IPv6 */
+       I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(135),
+       I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN */
+       I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */
+       I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(143),
+       I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */
+       I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(150),
+       I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+       /* unused entries */
+       I40E_PTT_UNUSED_ENTRY(154),
+       I40E_PTT_UNUSED_ENTRY(155),
+       I40E_PTT_UNUSED_ENTRY(156),
+       I40E_PTT_UNUSED_ENTRY(157),
+       I40E_PTT_UNUSED_ENTRY(158),
+       I40E_PTT_UNUSED_ENTRY(159),
+
+       I40E_PTT_UNUSED_ENTRY(160),
+       I40E_PTT_UNUSED_ENTRY(161),
+       I40E_PTT_UNUSED_ENTRY(162),
+       I40E_PTT_UNUSED_ENTRY(163),
+       I40E_PTT_UNUSED_ENTRY(164),
+       I40E_PTT_UNUSED_ENTRY(165),
+       I40E_PTT_UNUSED_ENTRY(166),
+       I40E_PTT_UNUSED_ENTRY(167),
+       I40E_PTT_UNUSED_ENTRY(168),
+       I40E_PTT_UNUSED_ENTRY(169),
+
+       I40E_PTT_UNUSED_ENTRY(170),
+       I40E_PTT_UNUSED_ENTRY(171),
+       I40E_PTT_UNUSED_ENTRY(172),
+       I40E_PTT_UNUSED_ENTRY(173),
+       I40E_PTT_UNUSED_ENTRY(174),
+       I40E_PTT_UNUSED_ENTRY(175),
+       I40E_PTT_UNUSED_ENTRY(176),
+       I40E_PTT_UNUSED_ENTRY(177),
+       I40E_PTT_UNUSED_ENTRY(178),
+       I40E_PTT_UNUSED_ENTRY(179),
+
+       I40E_PTT_UNUSED_ENTRY(180),
+       I40E_PTT_UNUSED_ENTRY(181),
+       I40E_PTT_UNUSED_ENTRY(182),
+       I40E_PTT_UNUSED_ENTRY(183),
+       I40E_PTT_UNUSED_ENTRY(184),
+       I40E_PTT_UNUSED_ENTRY(185),
+       I40E_PTT_UNUSED_ENTRY(186),
+       I40E_PTT_UNUSED_ENTRY(187),
+       I40E_PTT_UNUSED_ENTRY(188),
+       I40E_PTT_UNUSED_ENTRY(189),
+
+       I40E_PTT_UNUSED_ENTRY(190),
+       I40E_PTT_UNUSED_ENTRY(191),
+       I40E_PTT_UNUSED_ENTRY(192),
+       I40E_PTT_UNUSED_ENTRY(193),
+       I40E_PTT_UNUSED_ENTRY(194),
+       I40E_PTT_UNUSED_ENTRY(195),
+       I40E_PTT_UNUSED_ENTRY(196),
+       I40E_PTT_UNUSED_ENTRY(197),
+       I40E_PTT_UNUSED_ENTRY(198),
+       I40E_PTT_UNUSED_ENTRY(199),
+
+       I40E_PTT_UNUSED_ENTRY(200),
+       I40E_PTT_UNUSED_ENTRY(201),
+       I40E_PTT_UNUSED_ENTRY(202),
+       I40E_PTT_UNUSED_ENTRY(203),
+       I40E_PTT_UNUSED_ENTRY(204),
+       I40E_PTT_UNUSED_ENTRY(205),
+       I40E_PTT_UNUSED_ENTRY(206),
+       I40E_PTT_UNUSED_ENTRY(207),
+       I40E_PTT_UNUSED_ENTRY(208),
+       I40E_PTT_UNUSED_ENTRY(209),
+
+       I40E_PTT_UNUSED_ENTRY(210),
+       I40E_PTT_UNUSED_ENTRY(211),
+       I40E_PTT_UNUSED_ENTRY(212),
+       I40E_PTT_UNUSED_ENTRY(213),
+       I40E_PTT_UNUSED_ENTRY(214),
+       I40E_PTT_UNUSED_ENTRY(215),
+       I40E_PTT_UNUSED_ENTRY(216),
+       I40E_PTT_UNUSED_ENTRY(217),
+       I40E_PTT_UNUSED_ENTRY(218),
+       I40E_PTT_UNUSED_ENTRY(219),
+
+       I40E_PTT_UNUSED_ENTRY(220),
+       I40E_PTT_UNUSED_ENTRY(221),
+       I40E_PTT_UNUSED_ENTRY(222),
+       I40E_PTT_UNUSED_ENTRY(223),
+       I40E_PTT_UNUSED_ENTRY(224),
+       I40E_PTT_UNUSED_ENTRY(225),
+       I40E_PTT_UNUSED_ENTRY(226),
+       I40E_PTT_UNUSED_ENTRY(227),
+       I40E_PTT_UNUSED_ENTRY(228),
+       I40E_PTT_UNUSED_ENTRY(229),
+
+       I40E_PTT_UNUSED_ENTRY(230),
+       I40E_PTT_UNUSED_ENTRY(231),
+       I40E_PTT_UNUSED_ENTRY(232),
+       I40E_PTT_UNUSED_ENTRY(233),
+       I40E_PTT_UNUSED_ENTRY(234),
+       I40E_PTT_UNUSED_ENTRY(235),
+       I40E_PTT_UNUSED_ENTRY(236),
+       I40E_PTT_UNUSED_ENTRY(237),
+       I40E_PTT_UNUSED_ENTRY(238),
+       I40E_PTT_UNUSED_ENTRY(239),
+
+       I40E_PTT_UNUSED_ENTRY(240),
+       I40E_PTT_UNUSED_ENTRY(241),
+       I40E_PTT_UNUSED_ENTRY(242),
+       I40E_PTT_UNUSED_ENTRY(243),
+       I40E_PTT_UNUSED_ENTRY(244),
+       I40E_PTT_UNUSED_ENTRY(245),
+       I40E_PTT_UNUSED_ENTRY(246),
+       I40E_PTT_UNUSED_ENTRY(247),
+       I40E_PTT_UNUSED_ENTRY(248),
+       I40E_PTT_UNUSED_ENTRY(249),
+
+       I40E_PTT_UNUSED_ENTRY(250),
+       I40E_PTT_UNUSED_ENTRY(251),
+       I40E_PTT_UNUSED_ENTRY(252),
+       I40E_PTT_UNUSED_ENTRY(253),
+       I40E_PTT_UNUSED_ENTRY(254),
+       I40E_PTT_UNUSED_ENTRY(255)
+};
+
+
 /**
  * i40e_init_shared_code - Initialize the shared code
  * @hw: pointer to hardware structure
index 50730141bb7b2ea9c726ed070d641579fc9a28bd..036570d76176cd211ef2ee22328aeecd96b7174a 100644 (file)
@@ -332,6 +332,7 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
        u16 type;
        u16 length;
        u16 typelength;
+       u16 offset = 0;
 
        if (!lldpmib || !dcbcfg)
                return I40E_ERR_PARAM;
@@ -339,15 +340,17 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
        /* set to the start of LLDPDU */
        lldpmib += ETH_HLEN;
        tlv = (struct i40e_lldp_org_tlv *)lldpmib;
-       while (tlv) {
+       while (1) {
                typelength = ntohs(tlv->typelength);
                type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
                             I40E_LLDP_TLV_TYPE_SHIFT);
                length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
                               I40E_LLDP_TLV_LEN_SHIFT);
+               offset += sizeof(typelength) + length;
 
-               if (type == I40E_TLV_TYPE_END)
-                       break;/* END TLV break out */
+               /* END TLV or beyond LLDPDU size */
+               if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
+                       break;
 
                switch (type) {
                case I40E_TLV_TYPE_ORG:
index da22c3fa2c004a23adb8545ee01058d3dd0b2e3f..afd43d7973fa35da92ba11928ca6e06ecb0d5e4c 100644 (file)
@@ -1011,10 +1011,12 @@ static void i40e_dbg_dump_veb_all(struct i40e_pf *pf)
  **/
 static void i40e_dbg_cmd_fd_ctrl(struct i40e_pf *pf, u64 flag, bool enable)
 {
-       if (enable)
+       if (enable) {
                pf->flags |= flag;
-       else
+       } else {
                pf->flags &= ~flag;
+               pf->auto_disable_flags |= flag;
+       }
        dev_info(&pf->pdev->dev, "requesting a pf reset\n");
        i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED));
 }
@@ -1467,19 +1469,19 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                                 pf->msg_enable);
                }
        } else if (strncmp(cmd_buf, "pfr", 3) == 0) {
-               dev_info(&pf->pdev->dev, "forcing PFR\n");
+               dev_info(&pf->pdev->dev, "debugfs: forcing PFR\n");
                i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "corer", 5) == 0) {
-               dev_info(&pf->pdev->dev, "forcing CoreR\n");
+               dev_info(&pf->pdev->dev, "debugfs: forcing CoreR\n");
                i40e_do_reset_safe(pf, (1 << __I40E_CORE_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "globr", 5) == 0) {
-               dev_info(&pf->pdev->dev, "forcing GlobR\n");
+               dev_info(&pf->pdev->dev, "debugfs: forcing GlobR\n");
                i40e_do_reset_safe(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "empr", 4) == 0) {
-               dev_info(&pf->pdev->dev, "forcing EMPR\n");
+               dev_info(&pf->pdev->dev, "debugfs: forcing EMPR\n");
                i40e_do_reset_safe(pf, (1 << __I40E_EMP_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "read", 4) == 0) {
@@ -1663,28 +1665,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                desc = NULL;
        } else if ((strncmp(cmd_buf, "add fd_filter", 13) == 0) ||
                   (strncmp(cmd_buf, "rem fd_filter", 13) == 0)) {
-               struct i40e_fdir_data fd_data;
+               struct i40e_fdir_filter fd_data;
                u16 packet_len, i, j = 0;
                char *asc_packet;
+               u8 *raw_packet;
                bool add = false;
                int ret;
 
-               asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
+               if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+                       goto command_write_done;
+
+               if (strncmp(cmd_buf, "add", 3) == 0)
+                       add = true;
+
+               if (add && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED))
+                       goto command_write_done;
+
+               asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
                                     GFP_KERNEL);
                if (!asc_packet)
                        goto command_write_done;
 
-               fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
-                                            GFP_KERNEL);
+               raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
+                                    GFP_KERNEL);
 
-               if (!fd_data.raw_packet) {
+               if (!raw_packet) {
                        kfree(asc_packet);
                        asc_packet = NULL;
                        goto command_write_done;
                }
 
-               if (strncmp(cmd_buf, "add", 3) == 0)
-                       add = true;
                cnt = sscanf(&cmd_buf[13],
                             "%hx %2hhx %2hhx %hx %2hhx %2hhx %hx %x %hd %511s",
                             &fd_data.q_index,
@@ -1698,36 +1708,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                                 cnt);
                        kfree(asc_packet);
                        asc_packet = NULL;
-                       kfree(fd_data.raw_packet);
+                       kfree(raw_packet);
                        goto command_write_done;
                }
 
                /* fix packet length if user entered 0 */
                if (packet_len == 0)
-                       packet_len = I40E_FDIR_MAX_RAW_PACKET_LOOKUP;
+                       packet_len = I40E_FDIR_MAX_RAW_PACKET_SIZE;
 
                /* make sure to check the max as well */
                packet_len = min_t(u16,
-                                  packet_len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP);
+                                  packet_len, I40E_FDIR_MAX_RAW_PACKET_SIZE);
 
                for (i = 0; i < packet_len; i++) {
                        sscanf(&asc_packet[j], "%2hhx ",
-                              &fd_data.raw_packet[i]);
+                              &raw_packet[i]);
                        j += 3;
                }
                dev_info(&pf->pdev->dev, "FD raw packet dump\n");
                print_hex_dump(KERN_INFO, "FD raw packet: ",
                               DUMP_PREFIX_OFFSET, 16, 1,
-                              fd_data.raw_packet, packet_len, true);
-               ret = i40e_program_fdir_filter(&fd_data, pf, add);
+                              raw_packet, packet_len, true);
+               ret = i40e_program_fdir_filter(&fd_data, raw_packet, pf, add);
                if (!ret) {
                        dev_info(&pf->pdev->dev, "Filter command send Status : Success\n");
                } else {
                        dev_info(&pf->pdev->dev,
                                 "Filter command send failed %d\n", ret);
                }
-               kfree(fd_data.raw_packet);
-               fd_data.raw_packet = NULL;
+               kfree(raw_packet);
+               raw_packet = NULL;
                kfree(asc_packet);
                asc_packet = NULL;
        } else if (strncmp(cmd_buf, "fd-atr off", 10) == 0) {
index b1d7d8c5cb9b64a362a614f8a412698723582ae8..6049e63a826d2e67100f0c3e325945ec88873de3 100644 (file)
@@ -62,6 +62,9 @@ static const struct i40e_stats i40e_gstrings_net_stats[] = {
        I40E_NETDEV_STAT(rx_crc_errors),
 };
 
+static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
+                                    struct ethtool_rxnfc *cmd, bool add);
+
 /* These PF_STATs might look like duplicates of some NETDEV_STATs,
  * but they are separate.  This device supports Virtualization, and
  * as such might have several netdevs supporting VMDq and FCoE going
@@ -84,6 +87,7 @@ static struct i40e_stats i40e_gstrings_stats[] = {
        I40E_PF_STAT("illegal_bytes", stats.illegal_bytes),
        I40E_PF_STAT("mac_local_faults", stats.mac_local_faults),
        I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults),
+       I40E_PF_STAT("tx_timeout", tx_timeout_count),
        I40E_PF_STAT("rx_length_errors", stats.rx_length_errors),
        I40E_PF_STAT("link_xon_rx", stats.link_xon_rx),
        I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx),
@@ -649,18 +653,18 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
 
                /* process Tx ring statistics */
                do {
-                       start = u64_stats_fetch_begin_bh(&tx_ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
                        data[i] = tx_ring->stats.packets;
                        data[i + 1] = tx_ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&tx_ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
 
                /* Rx ring is the 2nd half of the queue pair */
                rx_ring = &tx_ring[1];
                do {
-                       start = u64_stats_fetch_begin_bh(&rx_ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
                        data[i + 2] = rx_ring->stats.packets;
                        data[i + 3] = rx_ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&rx_ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
        }
        rcu_read_unlock();
        if (vsi == pf->vsi[pf->lan_vsi]) {
@@ -1111,6 +1115,84 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
        return 0;
 }
 
+/**
+ * i40e_get_ethtool_fdir_all - Populates the rule count of a command
+ * @pf: Pointer to the physical function struct
+ * @cmd: The command to get or set Rx flow classification rules
+ * @rule_locs: Array of used rule locations
+ *
+ * This function populates both the total and actual rule count of
+ * the ethtool flow classification command
+ *
+ * Returns 0 on success or -EMSGSIZE if entry not found
+ **/
+static int i40e_get_ethtool_fdir_all(struct i40e_pf *pf,
+                                    struct ethtool_rxnfc *cmd,
+                                    u32 *rule_locs)
+{
+       struct i40e_fdir_filter *rule;
+       struct hlist_node *node2;
+       int cnt = 0;
+
+       /* report total rule count */
+       cmd->data = pf->hw.fdir_shared_filter_count +
+                   pf->fdir_pf_filter_count;
+
+       hlist_for_each_entry_safe(rule, node2,
+                                 &pf->fdir_filter_list, fdir_node) {
+               if (cnt == cmd->rule_cnt)
+                       return -EMSGSIZE;
+
+               rule_locs[cnt] = rule->fd_id;
+               cnt++;
+       }
+
+       cmd->rule_cnt = cnt;
+
+       return 0;
+}
+
+/**
+ * i40e_get_ethtool_fdir_entry - Look up a filter based on Rx flow
+ * @pf: Pointer to the physical function struct
+ * @cmd: The command to get or set Rx flow classification rules
+ *
+ * This function looks up a filter based on the Rx flow classification
+ * command and fills the flow spec info for it if found
+ *
+ * Returns 0 on success or -EINVAL if filter not found
+ **/
+static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
+                                      struct ethtool_rxnfc *cmd)
+{
+       struct ethtool_rx_flow_spec *fsp =
+                       (struct ethtool_rx_flow_spec *)&cmd->fs;
+       struct i40e_fdir_filter *rule = NULL;
+       struct hlist_node *node2;
+
+       /* report total rule count */
+       cmd->data = pf->hw.fdir_shared_filter_count +
+                   pf->fdir_pf_filter_count;
+
+       hlist_for_each_entry_safe(rule, node2,
+                                 &pf->fdir_filter_list, fdir_node) {
+               if (fsp->location <= rule->fd_id)
+                       break;
+       }
+
+       if (!rule || fsp->location != rule->fd_id)
+               return -EINVAL;
+
+       fsp->flow_type = rule->flow_type;
+       fsp->h_u.tcp_ip4_spec.psrc = rule->src_port;
+       fsp->h_u.tcp_ip4_spec.pdst = rule->dst_port;
+       fsp->h_u.tcp_ip4_spec.ip4src = rule->src_ip[0];
+       fsp->h_u.tcp_ip4_spec.ip4dst = rule->dst_ip[0];
+       fsp->ring_cookie = rule->q_index;
+
+       return 0;
+}
+
 /**
  * i40e_get_rxnfc - command to get RX flow classification rules
  * @netdev: network interface device structure
@@ -1135,15 +1217,15 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
                ret = i40e_get_rss_hash_opts(pf, cmd);
                break;
        case ETHTOOL_GRXCLSRLCNT:
-               cmd->rule_cnt = 10;
+               cmd->rule_cnt = pf->fdir_pf_active_filters;
                ret = 0;
                break;
        case ETHTOOL_GRXCLSRULE:
-               ret = 0;
+               ret = i40e_get_ethtool_fdir_entry(pf, cmd);
                break;
        case ETHTOOL_GRXCLSRLALL:
-               cmd->data = 500;
-               ret = 0;
+               ret = i40e_get_ethtool_fdir_all(pf, cmd, rule_locs);
+               break;
        default:
                break;
        }
@@ -1274,289 +1356,183 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
        return 0;
 }
 
-#define IP_HEADER_OFFSET 14
-#define I40E_UDPIP_DUMMY_PACKET_LEN 42
 /**
- * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required from the FDir descriptor
- * @ethtool_rx_flow_spec: the flow spec
- * @add: true adds a filter, false removes it
+ * i40e_match_fdir_input_set - Match a new filter against an existing one
+ * @rule: The filter already added
+ * @input: The new filter to comapre against
  *
- * Returns 0 if the filters were successfully added or removed
+ * Returns true if the two input set match
  **/
-static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
-                                  struct i40e_fdir_data *fd_data,
-                                  struct ethtool_rx_flow_spec *fsp, bool add)
+static bool i40e_match_fdir_input_set(struct i40e_fdir_filter *rule,
+                                     struct i40e_fdir_filter *input)
 {
-       struct i40e_pf *pf = vsi->back;
-       struct udphdr *udp;
-       struct iphdr *ip;
-       bool err = false;
-       int ret;
-       int i;
-       char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-                        0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11,
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                        0, 0, 0, 0, 0, 0, 0, 0};
-
-       memcpy(fd_data->raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN);
-
-       ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
-       udp = (struct udphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
-             + sizeof(struct iphdr));
-
-       ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
-       ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
-       udp->source = fsp->h_u.tcp_ip4_spec.psrc;
-       udp->dest = fsp->h_u.tcp_ip4_spec.pdst;
-
-       for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
-            i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) {
-               fd_data->pctype = i;
-               ret = i40e_program_fdir_filter(fd_data, pf, add);
-
-               if (ret) {
-                       dev_info(&pf->pdev->dev,
-                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
-                       err = true;
-               } else {
-                       dev_info(&pf->pdev->dev,
-                                "Filter OK for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
-               }
-       }
-
-       return err ? -EOPNOTSUPP : 0;
+       if ((rule->dst_ip[0] != input->dst_ip[0]) ||
+           (rule->src_ip[0] != input->src_ip[0]) ||
+           (rule->dst_port != input->dst_port) ||
+           (rule->src_port != input->src_port))
+               return false;
+       return true;
 }
 
-#define I40E_TCPIP_DUMMY_PACKET_LEN 54
 /**
- * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required from the FDir descriptor
- * @ethtool_rx_flow_spec: the flow spec
- * @add: true adds a filter, false removes it
+ * i40e_update_ethtool_fdir_entry - Updates the fdir filter entry
+ * @vsi: Pointer to the targeted VSI
+ * @input: The filter to update or NULL to indicate deletion
+ * @sw_idx: Software index to the filter
+ * @cmd: The command to get or set Rx flow classification rules
+ *
+ * This function updates (or deletes) a Flow Director entry from
+ * the hlist of the corresponding PF
  *
- * Returns 0 if the filters were successfully added or removed
+ * Returns 0 on success
  **/
-static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
-                                  struct i40e_fdir_data *fd_data,
-                                  struct ethtool_rx_flow_spec *fsp, bool add)
+static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi,
+                                         struct i40e_fdir_filter *input,
+                                         u16 sw_idx,
+                                         struct ethtool_rxnfc *cmd)
 {
+       struct i40e_fdir_filter *rule, *parent;
        struct i40e_pf *pf = vsi->back;
-       struct tcphdr *tcp;
-       struct iphdr *ip;
-       bool err = false;
-       int ret;
-       /* Dummy packet */
-       char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-                        0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6,
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                        0x80, 0x11, 0x0, 0x72, 0, 0, 0, 0};
-
-       memcpy(fd_data->raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN);
-
-       ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
-       tcp = (struct tcphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
-             + sizeof(struct iphdr));
-
-       ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
-       tcp->dest = fsp->h_u.tcp_ip4_spec.pdst;
-       ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
-       tcp->source = fsp->h_u.tcp_ip4_spec.psrc;
-
-       if (add) {
-               if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) {
-                       dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
-                       pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
-               }
-       }
+       struct hlist_node *node2;
+       int err = -EINVAL;
 
-       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
-       ret = i40e_program_fdir_filter(fd_data, pf, add);
+       parent = NULL;
+       rule = NULL;
 
-       if (ret) {
-               dev_info(&pf->pdev->dev,
-                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
-               err = true;
-       } else {
-               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
+       hlist_for_each_entry_safe(rule, node2,
+                                 &pf->fdir_filter_list, fdir_node) {
+               /* hash found, or no matching entry */
+               if (rule->fd_id >= sw_idx)
+                       break;
+               parent = rule;
        }
 
-       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
-
-       ret = i40e_program_fdir_filter(fd_data, pf, add);
-       if (ret) {
-               dev_info(&pf->pdev->dev,
-                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
-               err = true;
-       } else {
-               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
-                         fd_data->pctype, ret);
+       /* if there is an old rule occupying our place remove it */
+       if (rule && (rule->fd_id == sw_idx)) {
+               if (input && !i40e_match_fdir_input_set(rule, input))
+                       err = i40e_add_del_fdir(vsi, rule, false);
+               else if (!input)
+                       err = i40e_add_del_fdir(vsi, rule, false);
+               hlist_del(&rule->fdir_node);
+               kfree(rule);
+               pf->fdir_pf_active_filters--;
        }
 
-       return err ? -EOPNOTSUPP : 0;
-}
+       /* If no input this was a delete, err should be 0 if a rule was
+        * successfully found and removed from the list else -EINVAL
+        */
+       if (!input)
+               return err;
 
-/**
- * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required from the FDir descriptor
- * @ethtool_rx_flow_spec: the flow spec
- * @add: true adds a filter, false removes it
- *
- * Returns 0 if the filters were successfully added or removed
- **/
-static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
-                                   struct i40e_fdir_data *fd_data,
-                                   struct ethtool_rx_flow_spec *fsp, bool add)
-{
-       return -EOPNOTSUPP;
+       /* initialize node and set software index */
+       INIT_HLIST_NODE(&input->fdir_node);
+
+       /* add filter to the list */
+       if (parent)
+               hlist_add_after(&parent->fdir_node, &input->fdir_node);
+       else
+               hlist_add_head(&input->fdir_node,
+                              &pf->fdir_filter_list);
+
+       /* update counts */
+       pf->fdir_pf_active_filters++;
+
+       return 0;
 }
 
-#define I40E_IP_DUMMY_PACKET_LEN 34
 /**
- * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required for the FDir descriptor
- * @fsp: the ethtool flow spec
- * @add: true adds a filter, false removes it
+ * i40e_del_fdir_entry - Deletes a Flow Director filter entry
+ * @vsi: Pointer to the targeted VSI
+ * @cmd: The command to get or set Rx flow classification rules
  *
- * Returns 0 if the filters were successfully added or removed
- **/
-static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
-                                 struct i40e_fdir_data *fd_data,
-                                 struct ethtool_rx_flow_spec *fsp, bool add)
+ * The function removes a Flow Director filter entry from the
+ * hlist of the corresponding PF
+ *
+ * Returns 0 on success
+ */
+static int i40e_del_fdir_entry(struct i40e_vsi *vsi,
+                              struct ethtool_rxnfc *cmd)
 {
+       struct ethtool_rx_flow_spec *fsp =
+               (struct ethtool_rx_flow_spec *)&cmd->fs;
        struct i40e_pf *pf = vsi->back;
-       struct iphdr *ip;
-       bool err = false;
-       int ret;
-       int i;
-       char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-                        0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10,
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-       memcpy(fd_data->raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
-       ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
-
-       ip->saddr = fsp->h_u.usr_ip4_spec.ip4src;
-       ip->daddr = fsp->h_u.usr_ip4_spec.ip4dst;
-       ip->protocol = fsp->h_u.usr_ip4_spec.proto;
+       int ret = 0;
 
-       for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
-            i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) {
-               fd_data->pctype = i;
-               ret = i40e_program_fdir_filter(fd_data, pf, add);
+       ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd);
 
-               if (ret) {
-                       dev_info(&pf->pdev->dev,
-                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
-                       err = true;
-               } else {
-                       dev_info(&pf->pdev->dev,
-                                "Filter OK for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
-               }
-       }
-
-       return err ? -EOPNOTSUPP : 0;
+       i40e_fdir_check_and_reenable(pf);
+       return ret;
 }
 
 /**
- * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters for
- * a specific flow spec based on their protocol
+ * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters
  * @vsi: pointer to the targeted VSI
  * @cmd: command to get or set RX flow classification rules
  * @add: true adds a filter, false removes it
  *
- * Returns 0 if the filters were successfully added or removed
+ * Add/Remove Flow Director filters for a specific flow spec based on their
+ * protocol.  Returns 0 if the filters were successfully added or removed.
  **/
 static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
-                       struct ethtool_rxnfc *cmd, bool add)
+                                    struct ethtool_rxnfc *cmd, bool add)
 {
-       struct i40e_fdir_data fd_data;
-       int ret = -EINVAL;
+       struct ethtool_rx_flow_spec *fsp;
+       struct i40e_fdir_filter *input;
        struct i40e_pf *pf;
-       struct ethtool_rx_flow_spec *fsp =
-               (struct ethtool_rx_flow_spec *)&cmd->fs;
+       int ret = -EINVAL;
 
        if (!vsi)
                return -EINVAL;
 
        pf = vsi->back;
 
-       if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) &&
-           (fsp->ring_cookie >= vsi->num_queue_pairs))
-               return -EINVAL;
+       if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+               return -EOPNOTSUPP;
 
-       /* Populate the Flow Director that we have at the moment
-        * and allocate the raw packet buffer for the calling functions
-        */
-       fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
-                                    GFP_KERNEL);
+       if (add && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED))
+               return -ENOSPC;
 
-       if (!fd_data.raw_packet) {
-               dev_info(&pf->pdev->dev, "Could not allocate memory\n");
-               return -ENOMEM;
+       fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
+
+       if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort +
+                             pf->hw.func_caps.fd_filters_guaranteed)) {
+               return -EINVAL;
        }
 
-       fd_data.q_index = fsp->ring_cookie;
-       fd_data.flex_off = 0;
-       fd_data.pctype = 0;
-       fd_data.dest_vsi = vsi->id;
-       fd_data.dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
-       fd_data.fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID;
-       fd_data.cnt_index = 0;
-       fd_data.fd_id = 0;
+       if ((fsp->ring_cookie >= vsi->num_queue_pairs) && add)
+               return -EINVAL;
 
-       switch (fsp->flow_type & ~FLOW_EXT) {
-       case TCP_V4_FLOW:
-               ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
-               break;
-       case UDP_V4_FLOW:
-               ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
-               break;
-       case SCTP_V4_FLOW:
-               ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
-               break;
-       case IPV4_FLOW:
-               ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
-               break;
-       case IP_USER_FLOW:
-               switch (fsp->h_u.usr_ip4_spec.proto) {
-               case IPPROTO_TCP:
-                       ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
-                       break;
-               case IPPROTO_UDP:
-                       ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
-                       break;
-               case IPPROTO_SCTP:
-                       ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
-                       break;
-               default:
-                       ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
-                       break;
-               }
-               break;
-       default:
-               dev_info(&pf->pdev->dev, "Could not specify spec type\n");
-               ret = -EINVAL;
+       input = kzalloc(sizeof(*input), GFP_KERNEL);
+
+       if (!input)
+               return -ENOMEM;
+
+       input->fd_id = fsp->location;
+
+       input->q_index = fsp->ring_cookie;
+       input->flex_off = 0;
+       input->pctype = 0;
+       input->dest_vsi = vsi->id;
+       input->dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
+       input->fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID;
+       input->cnt_index = 0;
+       input->flow_type = fsp->flow_type;
+       input->ip4_proto = fsp->h_u.usr_ip4_spec.proto;
+       input->src_port = fsp->h_u.tcp_ip4_spec.psrc;
+       input->dst_port = fsp->h_u.tcp_ip4_spec.pdst;
+       input->src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
+       input->dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
+
+       ret = i40e_add_del_fdir(vsi, input, add);
+       if (ret) {
+               kfree(input);
+               return ret;
        }
 
-       kfree(fd_data.raw_packet);
-       fd_data.raw_packet = NULL;
+       if (!ret && add)
+               i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL);
+       else
+               kfree(input);
 
        return ret;
 }
@@ -1583,7 +1559,7 @@ static int i40e_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
                ret = i40e_add_del_fdir_ethtool(vsi, cmd, true);
                break;
        case ETHTOOL_SRXCLSRLDEL:
-               ret = i40e_add_del_fdir_ethtool(vsi, cmd, false);
+               ret = i40e_del_fdir_entry(vsi, cmd);
                break;
        default:
                break;
index 53f3ed2df7961c6623ff80c3a7672d9cc7f39562..3daaf205eabc034492412b498fcb25a297145bce 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 32
+#define DRV_VERSION_BUILD 34
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -376,20 +376,20 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
                        continue;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&tx_ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
                        packets = tx_ring->stats.packets;
                        bytes   = tx_ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&tx_ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
 
                stats->tx_packets += packets;
                stats->tx_bytes   += bytes;
                rx_ring = &tx_ring[1];
 
                do {
-                       start = u64_stats_fetch_begin_bh(&rx_ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
                        packets = rx_ring->stats.packets;
                        bytes   = rx_ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&rx_ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
 
                stats->rx_packets += packets;
                stats->rx_bytes   += bytes;
@@ -770,10 +770,10 @@ void i40e_update_stats(struct i40e_vsi *vsi)
                p = ACCESS_ONCE(vsi->tx_rings[q]);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&p->syncp);
+                       start = u64_stats_fetch_begin_irq(&p->syncp);
                        packets = p->stats.packets;
                        bytes = p->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&p->syncp, start));
                tx_b += bytes;
                tx_p += packets;
                tx_restart += p->tx_stats.restart_queue;
@@ -782,10 +782,10 @@ void i40e_update_stats(struct i40e_vsi *vsi)
                /* Rx queue is part of the same block as Tx queue */
                p = &p[1];
                do {
-                       start = u64_stats_fetch_begin_bh(&p->syncp);
+                       start = u64_stats_fetch_begin_irq(&p->syncp);
                        packets = p->stats.packets;
                        bytes = p->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&p->syncp, start));
                rx_b += bytes;
                rx_p += packets;
                rx_buf += p->rx_stats.alloc_buff_failed;
@@ -1965,11 +1965,14 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,
 
        netdev_info(netdev, "adding %pM vid=%d\n", netdev->dev_addr, vid);
 
-       /* If the network stack called us with vid = 0, we should
-        * indicate to i40e_vsi_add_vlan() that we want to receive
-        * any traffic (i.e. with any vlan tag, or untagged)
+       /* If the network stack called us with vid = 0 then
+        * it is asking to receive priority tagged packets with
+        * vlan id 0.  Our HW receives them by default when configured
+        * to receive untagged packets so there is no need to add an
+        * extra filter for vlan 0 tagged packets.
         */
-       ret = i40e_vsi_add_vlan(vsi, vid ? vid : I40E_VLAN_ANY);
+       if (vid)
+               ret = i40e_vsi_add_vlan(vsi, vid);
 
        if (!ret && (vid < VLAN_N_VID))
                set_bit(vid, vsi->active_vlans);
@@ -1982,7 +1985,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,
  * @netdev: network interface to be adjusted
  * @vid: vlan id to be removed
  *
- * net_device_ops implementation for adding vlan ids
+ * net_device_ops implementation for removing vlan ids
  **/
 static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
                                 __always_unused __be16 proto, u16 vid)
@@ -2420,6 +2423,28 @@ static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi)
                i40e_set_rx_mode(vsi->netdev);
 }
 
+/**
+ * i40e_fdir_filter_restore - Restore the Sideband Flow Director filters
+ * @vsi: Pointer to the targeted VSI
+ *
+ * This function replays the hlist on the hw where all the SB Flow Director
+ * filters were saved.
+ **/
+static void i40e_fdir_filter_restore(struct i40e_vsi *vsi)
+{
+       struct i40e_fdir_filter *filter;
+       struct i40e_pf *pf = vsi->back;
+       struct hlist_node *node;
+
+       if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+               return;
+
+       hlist_for_each_entry_safe(filter, node,
+                                 &pf->fdir_filter_list, fdir_node) {
+               i40e_add_del_fdir(vsi, filter, true);
+       }
+}
+
 /**
  * i40e_vsi_configure - Set up the VSI for action
  * @vsi: the VSI being configured
@@ -2558,7 +2583,7 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
        /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
        wr32(hw, I40E_PFINT_LNKLST0, 0);
 
-       /* Associate the queue pair to the vector and enable the q int */
+       /* Associate the queue pair to the vector and enable the queue int */
        val = I40E_QINT_RQCTL_CAUSE_ENA_MASK                  |
              (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
              (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
@@ -2867,8 +2892,7 @@ static irqreturn_t i40e_intr(int irq, void *data)
                         icr0_remaining);
                if ((icr0_remaining & I40E_PFINT_ICR0_PE_CRITERR_MASK) ||
                    (icr0_remaining & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) ||
-                   (icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK) ||
-                   (icr0_remaining & I40E_PFINT_ICR0_MAL_DETECT_MASK)) {
+                   (icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK)) {
                        dev_info(&pf->pdev->dev, "device will be reset\n");
                        set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
                        i40e_service_event_schedule(pf);
@@ -3731,8 +3755,8 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
                                          NULL);
        if (aq_ret) {
                dev_info(&vsi->back->pdev->dev,
-                        "%s: AQ command Config VSI BW allocation per TC failed = %d\n",
-                        __func__, vsi->back->hw.aq.asq_last_status);
+                        "AQ command Config VSI BW allocation per TC failed = %d\n",
+                        vsi->back->hw.aq.asq_last_status);
                return -EINVAL;
        }
 
@@ -4061,6 +4085,10 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
        } else if (vsi->netdev) {
                netdev_info(vsi->netdev, "NIC Link is Down\n");
        }
+
+       /* replay FDIR SB filters */
+       if (vsi->type == I40E_VSI_FDIR)
+               i40e_fdir_filter_restore(vsi);
        i40e_service_event_schedule(pf);
 
        return 0;
@@ -4267,6 +4295,26 @@ err_setup_tx:
        return err;
 }
 
+/**
+ * i40e_fdir_filter_exit - Cleans up the Flow Director accounting
+ * @pf: Pointer to pf
+ *
+ * This function destroys the hlist where all the Flow Director
+ * filters were saved.
+ **/
+static void i40e_fdir_filter_exit(struct i40e_pf *pf)
+{
+       struct i40e_fdir_filter *filter;
+       struct hlist_node *node2;
+
+       hlist_for_each_entry_safe(filter, node2,
+                                 &pf->fdir_filter_list, fdir_node) {
+               hlist_del(&filter->fdir_node);
+               kfree(filter);
+       }
+       pf->fdir_pf_active_filters = 0;
+}
+
 /**
  * i40e_close - Disables a network interface
  * @netdev: network interface device structure
@@ -4320,7 +4368,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
                 * for the warning interrupt will deal with the shutdown
                 * and recovery of the switch setup.
                 */
-               dev_info(&pf->pdev->dev, "GlobalR requested\n");
+               dev_dbg(&pf->pdev->dev, "GlobalR requested\n");
                val = rd32(&pf->hw, I40E_GLGEN_RTRIG);
                val |= I40E_GLGEN_RTRIG_GLOBR_MASK;
                wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
@@ -4331,7 +4379,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
                 *
                 * Same as Global Reset, except does *not* include the MAC/PHY
                 */
-               dev_info(&pf->pdev->dev, "CoreR requested\n");
+               dev_dbg(&pf->pdev->dev, "CoreR requested\n");
                val = rd32(&pf->hw, I40E_GLGEN_RTRIG);
                val |= I40E_GLGEN_RTRIG_CORER_MASK;
                wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
@@ -4365,7 +4413,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
                 * the switch, since we need to do all the recovery as
                 * for the Core Reset.
                 */
-               dev_info(&pf->pdev->dev, "PFR requested\n");
+               dev_dbg(&pf->pdev->dev, "PFR requested\n");
                i40e_handle_reset_warning(pf);
 
        } else if (reset_flags & (1 << __I40E_REINIT_REQUESTED)) {
@@ -4414,18 +4462,18 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
                           &old_cfg->etscfg.prioritytable,
                           sizeof(new_cfg->etscfg.prioritytable))) {
                        need_reconfig = true;
-                       dev_info(&pf->pdev->dev, "ETS UP2TC changed.\n");
+                       dev_dbg(&pf->pdev->dev, "ETS UP2TC changed.\n");
                }
 
                if (memcmp(&new_cfg->etscfg.tcbwtable,
                           &old_cfg->etscfg.tcbwtable,
                           sizeof(new_cfg->etscfg.tcbwtable)))
-                       dev_info(&pf->pdev->dev, "ETS TC BW Table changed.\n");
+                       dev_dbg(&pf->pdev->dev, "ETS TC BW Table changed.\n");
 
                if (memcmp(&new_cfg->etscfg.tsatable,
                           &old_cfg->etscfg.tsatable,
                           sizeof(new_cfg->etscfg.tsatable)))
-                       dev_info(&pf->pdev->dev, "ETS TSA Table changed.\n");
+                       dev_dbg(&pf->pdev->dev, "ETS TSA Table changed.\n");
        }
 
        /* Check if PFC configuration has changed */
@@ -4433,7 +4481,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
                   &old_cfg->pfc,
                   sizeof(new_cfg->pfc))) {
                need_reconfig = true;
-               dev_info(&pf->pdev->dev, "PFC config change detected.\n");
+               dev_dbg(&pf->pdev->dev, "PFC config change detected.\n");
        }
 
        /* Check if APP Table has changed */
@@ -4441,7 +4489,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
                   &old_cfg->app,
                   sizeof(new_cfg->app))) {
                need_reconfig = true;
-               dev_info(&pf->pdev->dev, "APP Table change detected.\n");
+               dev_dbg(&pf->pdev->dev, "APP Table change detected.\n");
        }
 
        return need_reconfig;
@@ -4491,7 +4539,7 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
 
        /* No change detected in DCBX configs */
        if (!memcmp(&tmp_dcbx_cfg, dcbx_cfg, sizeof(tmp_dcbx_cfg))) {
-               dev_info(&pf->pdev->dev, "No change detected in DCBX configuration.\n");
+               dev_dbg(&pf->pdev->dev, "No change detected in DCBX configuration.\n");
                goto exit;
        }
 
@@ -4549,8 +4597,8 @@ static void i40e_handle_lan_overflow_event(struct i40e_pf *pf,
        struct i40e_vf *vf;
        u16 vf_id;
 
-       dev_info(&pf->pdev->dev, "%s: Rx Queue Number = %d QTX_CTL=0x%08x\n",
-                __func__, queue, qtx_ctl);
+       dev_dbg(&pf->pdev->dev, "overflow Rx Queue Number = %d QTX_CTL=0x%08x\n",
+               queue, qtx_ctl);
 
        /* Queue belongs to VF, find the VF and issue VF reset */
        if (((qtx_ctl & I40E_QTX_CTL_PFVF_Q_MASK)
@@ -4579,6 +4627,54 @@ static void i40e_service_event_complete(struct i40e_pf *pf)
        clear_bit(__I40E_SERVICE_SCHED, &pf->state);
 }
 
+/**
+ * i40e_get_current_fd_count - Get the count of FD filters programmed in the HW
+ * @pf: board private structure
+ **/
+int i40e_get_current_fd_count(struct i40e_pf *pf)
+{
+       int val, fcnt_prog;
+       val = rd32(&pf->hw, I40E_PFQF_FDSTAT);
+       fcnt_prog = (val & I40E_PFQF_FDSTAT_GUARANT_CNT_MASK) +
+                   ((val & I40E_PFQF_FDSTAT_BEST_CNT_MASK) >>
+                     I40E_PFQF_FDSTAT_BEST_CNT_SHIFT);
+       return fcnt_prog;
+}
+
+/**
+ * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled
+ * @pf: board private structure
+ **/
+void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
+{
+       u32 fcnt_prog, fcnt_avail;
+
+       /* Check if, FD SB or ATR was auto disabled and if there is enough room
+        * to re-enable
+        */
+       if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+           (pf->flags & I40E_FLAG_FD_SB_ENABLED))
+               return;
+       fcnt_prog = i40e_get_current_fd_count(pf);
+       fcnt_avail = pf->hw.fdir_shared_filter_count +
+                                              pf->fdir_pf_filter_count;
+       if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) {
+               if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
+                   (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) {
+                       pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
+                       dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
+               }
+       }
+       /* Wait for some more space to be available to turn on ATR */
+       if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM * 2)) {
+               if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+                   (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) {
+                       pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                       dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table now\n");
+               }
+       }
+}
+
 /**
  * i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table
  * @pf: board private structure
@@ -4588,11 +4684,14 @@ static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
        if (!(pf->flags & I40E_FLAG_FDIR_REQUIRES_REINIT))
                return;
 
-       pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
-
        /* if interface is down do nothing */
        if (test_bit(__I40E_DOWN, &pf->state))
                return;
+       i40e_fdir_check_and_reenable(pf);
+
+       if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+           (pf->flags & I40E_FLAG_FD_SB_ENABLED))
+               pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
 }
 
 /**
@@ -4902,7 +5001,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
                                        event.msg_size);
                        break;
                case i40e_aqc_opc_lldp_update_mib:
-                       dev_info(&pf->pdev->dev, "ARQ: Update LLDP MIB event received\n");
+                       dev_dbg(&pf->pdev->dev, "ARQ: Update LLDP MIB event received\n");
 #ifdef CONFIG_I40E_DCB
                        rtnl_lock();
                        ret = i40e_handle_lldp_event(pf, &event);
@@ -4910,7 +5009,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
 #endif /* CONFIG_I40E_DCB */
                        break;
                case i40e_aqc_opc_event_lan_overflow:
-                       dev_info(&pf->pdev->dev, "ARQ LAN queue overflow event received\n");
+                       dev_dbg(&pf->pdev->dev, "ARQ LAN queue overflow event received\n");
                        i40e_handle_lan_overflow_event(pf, &event);
                        break;
                case i40e_aqc_opc_send_msg_to_peer:
@@ -5052,6 +5151,12 @@ static int i40e_get_capabilities(struct i40e_pf *pf)
        /* increment MSI-X count because current FW skips one */
        pf->hw.func_caps.num_msix_vectors++;
 
+       if (((pf->hw.aq.fw_maj_ver == 2) && (pf->hw.aq.fw_min_ver < 22)) ||
+           (pf->hw.aq.fw_maj_ver < 2)) {
+               pf->hw.func_caps.num_msix_vectors++;
+               pf->hw.func_caps.num_msix_vectors_vf++;
+       }
+
        if (pf->hw.debug_mask & I40E_DEBUG_USER)
                dev_info(&pf->pdev->dev,
                         "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n",
@@ -5131,9 +5236,9 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
                err = i40e_up_complete(vsi);
                if (err)
                        goto err_up_complete;
+               clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
        }
 
-       clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
        return;
 
 err_up_complete:
@@ -5156,6 +5261,7 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)
 {
        int i;
 
+       i40e_fdir_filter_exit(pf);
        for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
                if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
                        i40e_vsi_release(pf->vsi[i]);
@@ -5180,7 +5286,7 @@ static int i40e_prep_for_reset(struct i40e_pf *pf)
        if (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))
                return 0;
 
-       dev_info(&pf->pdev->dev, "Tearing down internal switch for reset\n");
+       dev_dbg(&pf->pdev->dev, "Tearing down internal switch for reset\n");
 
        if (i40e_check_asq_alive(hw))
                i40e_vc_notify_reset(pf);
@@ -5227,7 +5333,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
 
        if (test_bit(__I40E_DOWN, &pf->state))
                goto end_core_reset;
-       dev_info(&pf->pdev->dev, "Rebuilding internal switch\n");
+       dev_dbg(&pf->pdev->dev, "Rebuilding internal switch\n");
 
        /* rebuild the basics for the AdminQ, HMC, and initial HW switch */
        ret = i40e_init_adminq(&pf->hw);
@@ -5277,7 +5383,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
         * try to recover minimal use by getting the basic PF VSI working.
         */
        if (pf->vsi[pf->lan_vsi]->uplink_seid != pf->mac_seid) {
-               dev_info(&pf->pdev->dev, "attempting to rebuild switch\n");
+               dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n");
                /* find the one VEB connected to the MAC, and find orphans */
                for (v = 0; v < I40E_MAX_VEB; v++) {
                        if (!pf->veb[v])
@@ -5342,7 +5448,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        dv.subbuild_version = 0;
        i40e_aq_send_driver_version(&pf->hw, &dv, NULL);
 
-       dev_info(&pf->pdev->dev, "PF reset done\n");
+       dev_info(&pf->pdev->dev, "reset complete\n");
 
 end_core_reset:
        clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state);
@@ -5391,7 +5497,7 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK)
                                >> I40E_GL_MDET_TX_QUEUE_SHIFT;
                dev_info(&pf->pdev->dev,
-                        "Malicious Driver Detection TX event 0x%02x on q %d of function 0x%02x\n",
+                        "Malicious Driver Detection event 0x%02x on TX queue %d of function 0x%02x\n",
                         event, queue, func);
                wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
                mdd_detected = true;
@@ -5405,7 +5511,7 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK)
                                >> I40E_GL_MDET_RX_QUEUE_SHIFT;
                dev_info(&pf->pdev->dev,
-                        "Malicious Driver Detection RX event 0x%02x on q %d of function 0x%02x\n",
+                        "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n",
                         event, queue, func);
                wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
                mdd_detected = true;
@@ -6242,12 +6348,8 @@ static int i40e_sw_init(struct i40e_pf *pf)
            (pf->hw.func_caps.fd_filters_best_effort > 0)) {
                pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
                pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE;
-               dev_info(&pf->pdev->dev,
-                       "Flow Director ATR mode Enabled\n");
                if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) {
                        pf->flags |= I40E_FLAG_FD_SB_ENABLED;
-                       dev_info(&pf->pdev->dev,
-                                "Flow Director Side Band mode Enabled\n");
                } else {
                        dev_info(&pf->pdev->dev,
                                 "Flow Director Side Band mode Disabled in MFP mode\n");
@@ -6271,9 +6373,6 @@ static int i40e_sw_init(struct i40e_pf *pf)
                pf->num_req_vfs = min_t(int,
                                        pf->hw.func_caps.num_vfs,
                                        I40E_MAX_VF_COUNT);
-               dev_info(&pf->pdev->dev,
-                        "Number of VFs being requested for PF[%d] = %d\n",
-                        pf->hw.pf_id, pf->num_req_vfs);
        }
 #endif /* CONFIG_PCI_IOV */
        pf->eeprom_version = 0xDEAD;
@@ -6479,10 +6578,9 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
        np = netdev_priv(netdev);
        np->vsi = vsi;
 
-       netdev->hw_enc_features = NETIF_F_IP_CSUM        |
+       netdev->hw_enc_features |= NETIF_F_IP_CSUM       |
                                  NETIF_F_GSO_UDP_TUNNEL |
-                                 NETIF_F_TSO            |
-                                 NETIF_F_SG;
+                                 NETIF_F_TSO;
 
        netdev->features = NETIF_F_SG                  |
                           NETIF_F_IP_CSUM             |
@@ -6755,8 +6853,6 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
                        if (vsi->netdev) {
                                /* results in a call to i40e_close() */
                                unregister_netdev(vsi->netdev);
-                               free_netdev(vsi->netdev);
-                               vsi->netdev = NULL;
                        }
                } else {
                        if (!test_and_set_bit(__I40E_DOWN, &vsi->state))
@@ -6775,6 +6871,10 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
 
        i40e_vsi_delete(vsi);
        i40e_vsi_free_q_vectors(vsi);
+       if (vsi->netdev) {
+               free_netdev(vsi->netdev);
+               vsi->netdev = NULL;
+       }
        i40e_vsi_clear_rings(vsi);
        i40e_vsi_clear(vsi);
 
@@ -6829,8 +6929,7 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi)
        }
 
        if (vsi->base_vector) {
-               dev_info(&pf->pdev->dev,
-                        "VSI %d has non-zero base vector %d\n",
+               dev_info(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n",
                         vsi->seid, vsi->base_vector);
                return -EEXIST;
        }
@@ -6849,7 +6948,7 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi)
                                                 vsi->num_q_vectors, vsi->idx);
        if (vsi->base_vector < 0) {
                dev_info(&pf->pdev->dev,
-                        "failed to get q tracking for VSI %d, err=%d\n",
+                        "failed to get queue tracking for VSI %d, err=%d\n",
                         vsi->seid, vsi->base_vector);
                i40e_vsi_free_q_vectors(vsi);
                ret = -ENOENT;
@@ -7806,6 +7905,44 @@ static int i40e_setup_pf_filter_control(struct i40e_pf *pf)
        return 0;
 }
 
+#define INFO_STRING_LEN 255
+static void i40e_print_features(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       char *buf, *string;
+
+       string = kzalloc(INFO_STRING_LEN, GFP_KERNEL);
+       if (!string) {
+               dev_err(&pf->pdev->dev, "Features string allocation failed\n");
+               return;
+       }
+
+       buf = string;
+
+       buf += sprintf(string, "Features: PF-id[%d] ", hw->pf_id);
+#ifdef CONFIG_PCI_IOV
+       buf += sprintf(buf, "VFs: %d ", pf->num_req_vfs);
+#endif
+       buf += sprintf(buf, "VSIs: %d QP: %d ", pf->hw.func_caps.num_vsis,
+                      pf->vsi[pf->lan_vsi]->num_queue_pairs);
+
+       if (pf->flags & I40E_FLAG_RSS_ENABLED)
+               buf += sprintf(buf, "RSS ");
+       buf += sprintf(buf, "FDir ");
+       if (pf->flags & I40E_FLAG_FD_ATR_ENABLED)
+               buf += sprintf(buf, "ATR ");
+       if (pf->flags & I40E_FLAG_FD_SB_ENABLED)
+               buf += sprintf(buf, "NTUPLE ");
+       if (pf->flags & I40E_FLAG_DCB_ENABLED)
+               buf += sprintf(buf, "DCB ");
+       if (pf->flags & I40E_FLAG_PTP)
+               buf += sprintf(buf, "PTP ");
+
+       BUG_ON(buf > (string + INFO_STRING_LEN));
+       dev_info(&pf->pdev->dev, "%s\n", string);
+       kfree(string);
+}
+
 /**
  * i40e_probe - Device initialization routine
  * @pdev: PCI device information struct
@@ -7832,16 +7969,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                return err;
 
        /* set up for high or low dma */
-       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
-               /* coherent mask for the same size will always succeed if
-                * dma_set_mask does
-                */
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
-       } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-       } else {
-               dev_err(&pdev->dev, "DMA configuration failed: %d\n", err);
-               err = -EIO;
+       err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+       if (err)
+               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (err) {
+               dev_err(&pdev->dev,
+                       "DMA configuration failed: 0x%x\n", err);
                goto err_dma;
        }
 
@@ -7930,13 +8063,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        err = i40e_init_adminq(hw);
        dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw));
-       if (((hw->nvm.version & I40E_NVM_VERSION_HI_MASK)
-                >> I40E_NVM_VERSION_HI_SHIFT) != I40E_CURRENT_NVM_VERSION_HI) {
-               dev_info(&pdev->dev,
-                        "warning: NVM version not supported, supported version: %02x.%02x\n",
-                        I40E_CURRENT_NVM_VERSION_HI,
-                        I40E_CURRENT_NVM_VERSION_LO);
-       }
        if (err) {
                dev_info(&pdev->dev,
                         "init_adminq failed: %d expecting API %02x.%02x\n",
@@ -8086,7 +8212,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        i40e_set_pci_config_data(hw, link_status);
 
-       dev_info(&pdev->dev, "PCI Express: %s %s\n",
+       dev_info(&pdev->dev, "PCI-Express: %s %s\n",
                (hw->bus.speed == i40e_bus_speed_8000 ? "Speed 8.0GT/s" :
                 hw->bus.speed == i40e_bus_speed_5000 ? "Speed 5.0GT/s" :
                 hw->bus.speed == i40e_bus_speed_2500 ? "Speed 2.5GT/s" :
@@ -8103,6 +8229,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_warn(&pdev->dev, "Please move the device to a different PCI-e link with more lanes and/or higher transfer rate.\n");
        }
 
+       /* print a string summarizing features */
+       i40e_print_features(pf);
+
        return 0;
 
        /* Unwind what we've done if something failed in the setup */
index 73f95b081927c13413f7a006a6638195b3929507..262bdf11d221e5a30be53a2f57a09e1865b32e79 100644 (file)
 #include "i40e_prototype.h"
 
 /**
- *  i40e_init_nvm_ops - Initialize NVM function pointers.
- *  @hw: pointer to the HW structure.
+ * i40e_init_nvm_ops - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
  *
- *  Setups the function pointers and the NVM info structure. Should be called
- *  once per NVM initialization, e.g. inside the i40e_init_shared_code().
- *  Please notice that the NVM term is used here (& in all methods covered
- *  in this file) as an equivalent of the FLASH part mapped into the SR.
- *  We are accessing FLASH always thru the Shadow RAM.
+ * Setup the function pointers and the NVM info structure. Should be called
+ * once per NVM initialization, e.g. inside the i40e_init_shared_code().
+ * Please notice that the NVM term is used here (& in all methods covered
+ * in this file) as an equivalent of the FLASH part mapped into the SR.
+ * We are accessing FLASH always thru the Shadow RAM.
  **/
 i40e_status i40e_init_nvm(struct i40e_hw *hw)
 {
@@ -49,16 +49,16 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw)
        gens = rd32(hw, I40E_GLNVM_GENS);
        sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
                           I40E_GLNVM_GENS_SR_SIZE_SHIFT);
-       /* Switching to words (sr_size contains power of 2KB). */
+       /* Switching to words (sr_size contains power of 2KB) */
        nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB;
 
-       /* Check if we are in the normal or blank NVM programming mode. */
+       /* Check if we are in the normal or blank NVM programming mode */
        fla = rd32(hw, I40E_GLNVM_FLA);
-       if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode. */
-               /* Max NVM timeout. */
+       if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
+               /* Max NVM timeout */
                nvm->timeout = I40E_MAX_NVM_TIMEOUT;
                nvm->blank_nvm_mode = false;
-       } else { /* Blank programming mode. */
+       } else { /* Blank programming mode */
                nvm->blank_nvm_mode = true;
                ret_code = I40E_ERR_NVM_BLANK_MODE;
                hw_dbg(hw, "NVM init error: unsupported blank mode.\n");
@@ -68,12 +68,12 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw)
 }
 
 /**
- *  i40e_acquire_nvm - Generic request for acquiring the NVM ownership.
- *  @hw: pointer to the HW structure.
- *  @access: NVM access type (read or write).
+ * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
+ * @hw: pointer to the HW structure
+ * @access: NVM access type (read or write)
  *
- *  This function will request NVM ownership for reading
- *  via the proper Admin Command.
+ * This function will request NVM ownership for reading
+ * via the proper Admin Command.
  **/
 i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
                                       enum i40e_aq_resource_access_type access)
@@ -87,20 +87,20 @@ i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
 
        ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
                                            0, &time, NULL);
-       /* Reading the Global Device Timer. */
+       /* Reading the Global Device Timer */
        gtime = rd32(hw, I40E_GLVFGEN_TIMER);
 
-       /* Store the timeout. */
+       /* Store the timeout */
        hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime;
 
        if (ret_code) {
-               /* Set the polling timeout. */
+               /* Set the polling timeout */
                if (time > I40E_MAX_NVM_TIMEOUT)
                        timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT)
                                  + gtime;
                else
                        timeout = hw->nvm.hw_semaphore_timeout;
-               /* Poll until the current NVM owner timeouts. */
+               /* Poll until the current NVM owner timeouts */
                while (gtime < timeout) {
                        usleep_range(10000, 20000);
                        ret_code = i40e_aq_request_resource(hw,
@@ -128,10 +128,10 @@ i40e_i40e_acquire_nvm_exit:
 }
 
 /**
- *  i40e_release_nvm - Generic request for releasing the NVM ownership.
- *  @hw: pointer to the HW structure.
+ * i40e_release_nvm - Generic request for releasing the NVM ownership
+ * @hw: pointer to the HW structure
  *
- *  This function will release NVM resource via the proper Admin Command.
+ * This function will release NVM resource via the proper Admin Command.
  **/
 void i40e_release_nvm(struct i40e_hw *hw)
 {
@@ -140,17 +140,17 @@ void i40e_release_nvm(struct i40e_hw *hw)
 }
 
 /**
- *  i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit.
- *  @hw: pointer to the HW structure.
+ * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
+ * @hw: pointer to the HW structure
  *
- *  Polls the SRCTL Shadow RAM register done bit.
+ * Polls the SRCTL Shadow RAM register done bit.
  **/
 static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
 {
        i40e_status ret_code = I40E_ERR_TIMEOUT;
        u32 srctl, wait_cnt;
 
-       /* Poll the I40E_GLNVM_SRCTL until the done bit is set. */
+       /* Poll the I40E_GLNVM_SRCTL until the done bit is set */
        for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
                srctl = rd32(hw, I40E_GLNVM_SRCTL);
                if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
@@ -165,12 +165,12 @@ static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
 }
 
 /**
- *  i40e_read_nvm_word - Reads Shadow RAM
- *  @hw: pointer to the HW structure.
- *  @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
- *  @data: word read from the Shadow RAM.
+ * i40e_read_nvm_word - Reads Shadow RAM
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
+ * @data: word read from the Shadow RAM
  *
- *  Reads 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
+ * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
  **/
 i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
                                         u16 *data)
@@ -184,15 +184,15 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
                goto read_nvm_exit;
        }
 
-       /* Poll the done bit first. */
+       /* Poll the done bit first */
        ret_code = i40e_poll_sr_srctl_done_bit(hw);
        if (!ret_code) {
-               /* Write the address and start reading. */
+               /* Write the address and start reading */
                sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
                         (1 << I40E_GLNVM_SRCTL_START_SHIFT);
                wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
 
-               /* Poll I40E_GLNVM_SRCTL until the done bit is set. */
+               /* Poll I40E_GLNVM_SRCTL until the done bit is set */
                ret_code = i40e_poll_sr_srctl_done_bit(hw);
                if (!ret_code) {
                        sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
@@ -210,16 +210,15 @@ read_nvm_exit:
 }
 
 /**
- *  i40e_read_nvm_buffer - Reads Shadow RAM buffer.
- *  @hw: pointer to the HW structure.
- *  @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
- *  @words: number of words to read (in) &
- *          number of words read before the NVM ownership timeout (out).
- *  @data: words read from the Shadow RAM.
+ * i40e_read_nvm_buffer - Reads Shadow RAM buffer
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
+ * @words: (in) number of words to read; (out) number of words actually read
+ * @data: words read from the Shadow RAM
  *
- *  Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
- *  method. The buffer read is preceded by the NVM ownership take
- *  and followed by the release.
+ * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
+ * method. The buffer read is preceded by the NVM ownership take
+ * and followed by the release.
  **/
 i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
                                           u16 *words, u16 *data)
@@ -227,7 +226,7 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
        i40e_status ret_code = 0;
        u16 index, word;
 
-       /* Loop thru the selected region. */
+       /* Loop thru the selected region */
        for (word = 0; word < *words; word++) {
                index = offset + word;
                ret_code = i40e_read_nvm_word(hw, index, &data[word]);
@@ -235,21 +234,21 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
                        break;
        }
 
-       /* Update the number of words read from the Shadow RAM. */
+       /* Update the number of words read from the Shadow RAM */
        *words = word;
 
        return ret_code;
 }
 
 /**
- *  i40e_calc_nvm_checksum - Calculates and returns the checksum
- *  @hw: pointer to hardware structure
- *  @checksum: pointer to the checksum
+ * 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
- *  is customer specific and unknown. Therefore, this function skips all maximum
- *  possible size of VPD (1kB).
+ * This function calculates SW Checksum that covers the whole 64kB shadow RAM
+ * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
+ * is customer specific and unknown. Therefore, this function skips all maximum
+ * possible size of VPD (1kB).
  **/
 static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,
                                                    u16 *checksum)
@@ -311,12 +310,12 @@ i40e_calc_nvm_checksum_exit:
 }
 
 /**
- *  i40e_validate_nvm_checksum - Validate EEPROM checksum
- *  @hw: pointer to hardware structure
- *  @checksum: calculated checksum
+ * i40e_validate_nvm_checksum - Validate EEPROM checksum
+ * @hw: pointer to hardware structure
+ * @checksum: calculated checksum
  *
- *  Performs checksum calculation and validates the NVM SW checksum. If the
- *  caller does not need checksum, the value can be NULL.
+ * Performs checksum calculation and validates the NVM SW checksum. If the
+ * caller does not need checksum, the value can be NULL.
  **/
 i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
                                                 u16 *checksum)
index ed91f93ede2bd6bc839676560e3da077a873a245..9cd57e617959b1622ec57f8c8f6e2146c9c800a6 100644 (file)
@@ -231,6 +231,13 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
                                                 u16 *checksum);
 void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status);
 
+extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[];
+
+static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
+{
+       return i40e_ptype_lookup[ptype];
+}
+
 /* prototype for functions used for SW locks */
 
 /* i40e_common for VF drivers*/
index 19af4ce0a4fe655001c60a43b02339bb188ba3aa..88666adb07436faf2ffae7a8fac2be319ef03ace 100644 (file)
@@ -25,6 +25,7 @@
  ******************************************************************************/
 
 #include "i40e.h"
+#include "i40e_prototype.h"
 
 static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
                                u32 td_tag)
@@ -39,11 +40,12 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
 #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
 /**
  * i40e_program_fdir_filter - Program a Flow Director filter
- * @fdir_input: Packet data that will be filter parameters
+ * @fdir_data: Packet data that will be filter parameters
+ * @raw_packet: the pre-allocated packet buffer for FDir
  * @pf: The pf pointer
  * @add: True for add/update, False for remove
  **/
-int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
+int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
                             struct i40e_pf *pf, bool add)
 {
        struct i40e_filter_program_desc *fdir_desc;
@@ -68,8 +70,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
        tx_ring = vsi->tx_rings[0];
        dev = tx_ring->dev;
 
-       dma = dma_map_single(dev, fdir_data->raw_packet,
-                            I40E_FDIR_MAX_RAW_PACKET_LOOKUP, DMA_TO_DEVICE);
+       dma = dma_map_single(dev, raw_packet,
+                            I40E_FDIR_MAX_RAW_PACKET_SIZE, DMA_TO_DEVICE);
        if (dma_mapping_error(dev, dma))
                goto dma_fail;
 
@@ -132,14 +134,14 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
        tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0;
 
        /* record length, and DMA address */
-       dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP);
+       dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_SIZE);
        dma_unmap_addr_set(tx_buf, dma, dma);
 
        tx_desc->buffer_addr = cpu_to_le64(dma);
        td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY;
 
        tx_desc->cmd_type_offset_bsz =
-               build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_LOOKUP, 0);
+               build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0);
 
        /* set the timestamp */
        tx_buf->time_stamp = jiffies;
@@ -161,26 +163,328 @@ dma_fail:
        return -1;
 }
 
+#define IP_HEADER_OFFSET 14
+#define I40E_UDPIP_DUMMY_PACKET_LEN 42
+/**
+ * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 filters
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
+                                  struct i40e_fdir_filter *fd_data,
+                                  u8 *raw_packet, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct udphdr *udp;
+       struct iphdr *ip;
+       bool err = false;
+       int ret;
+       int i;
+       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
+               0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+       memcpy(raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN);
+
+       ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+       udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET
+             + sizeof(struct iphdr));
+
+       ip->daddr = fd_data->dst_ip[0];
+       udp->dest = fd_data->dst_port;
+       ip->saddr = fd_data->src_ip[0];
+       udp->source = fd_data->src_port;
+
+       for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
+            i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) {
+               fd_data->pctype = i;
+               ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+                       err = true;
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "Filter OK for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+               }
+       }
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+#define I40E_TCPIP_DUMMY_PACKET_LEN 54
+/**
+ * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 filters
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
+                                  struct i40e_fdir_filter *fd_data,
+                                  u8 *raw_packet, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct tcphdr *tcp;
+       struct iphdr *ip;
+       bool err = false;
+       int ret;
+       /* Dummy packet */
+       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
+               0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x11,
+               0x0, 0x72, 0, 0, 0, 0};
+
+       memcpy(raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN);
+
+       ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+       tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET
+             + sizeof(struct iphdr));
+
+       ip->daddr = fd_data->dst_ip[0];
+       tcp->dest = fd_data->dst_port;
+       ip->saddr = fd_data->src_ip[0];
+       tcp->source = fd_data->src_port;
+
+       if (add) {
+               if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) {
+                       dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
+                       pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+               }
+       }
+
+       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
+       ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                        fd_data->pctype, ret);
+               err = true;
+       } else {
+               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
+                        fd_data->pctype, ret);
+       }
+
+       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+
+       ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                        fd_data->pctype, ret);
+               err = true;
+       } else {
+               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
+                         fd_data->pctype, ret);
+       }
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
+                                   struct i40e_fdir_filter *fd_data,
+                                   u8 *raw_packet, bool add)
+{
+       return -EOPNOTSUPP;
+}
+
+#define I40E_IP_DUMMY_PACKET_LEN 34
+/**
+ * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
+                                 struct i40e_fdir_filter *fd_data,
+                                 u8 *raw_packet, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct iphdr *ip;
+       bool err = false;
+       int ret;
+       int i;
+       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
+               0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0};
+
+       memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
+       ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+
+       ip->saddr = fd_data->src_ip[0];
+       ip->daddr = fd_data->dst_ip[0];
+       ip->protocol = 0;
+
+       for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
+            i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) {
+               fd_data->pctype = i;
+               ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+                       err = true;
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "Filter OK for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+               }
+       }
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * i40e_add_del_fdir - Build raw packets to add/del fdir filter
+ * @vsi: pointer to the targeted VSI
+ * @cmd: command to get or set RX flow classification rules
+ * @add: true adds a filter, false removes it
+ *
+ **/
+int i40e_add_del_fdir(struct i40e_vsi *vsi,
+                     struct i40e_fdir_filter *input, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       u8 *raw_packet;
+       int ret;
+
+       /* Populate the Flow Director that we have at the moment
+        * and allocate the raw packet buffer for the calling functions
+        */
+       raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
+       if (!raw_packet)
+               return -ENOMEM;
+
+       switch (input->flow_type & ~FLOW_EXT) {
+       case TCP_V4_FLOW:
+               ret = i40e_add_del_fdir_tcpv4(vsi, input, raw_packet,
+                                             add);
+               break;
+       case UDP_V4_FLOW:
+               ret = i40e_add_del_fdir_udpv4(vsi, input, raw_packet,
+                                             add);
+               break;
+       case SCTP_V4_FLOW:
+               ret = i40e_add_del_fdir_sctpv4(vsi, input, raw_packet,
+                                              add);
+               break;
+       case IPV4_FLOW:
+               ret = i40e_add_del_fdir_ipv4(vsi, input, raw_packet,
+                                            add);
+               break;
+       case IP_USER_FLOW:
+               switch (input->ip4_proto) {
+               case IPPROTO_TCP:
+                       ret = i40e_add_del_fdir_tcpv4(vsi, input,
+                                                     raw_packet, add);
+                       break;
+               case IPPROTO_UDP:
+                       ret = i40e_add_del_fdir_udpv4(vsi, input,
+                                                     raw_packet, add);
+                       break;
+               case IPPROTO_SCTP:
+                       ret = i40e_add_del_fdir_sctpv4(vsi, input,
+                                                      raw_packet, add);
+                       break;
+               default:
+                       ret = i40e_add_del_fdir_ipv4(vsi, input,
+                                                    raw_packet, add);
+                       break;
+               }
+               break;
+       default:
+               dev_info(&pf->pdev->dev, "Could not specify spec type %d",
+                        input->flow_type);
+               ret = -EINVAL;
+       }
+
+       kfree(raw_packet);
+       return ret;
+}
+
 /**
  * i40e_fd_handle_status - check the Programming Status for FD
  * @rx_ring: the Rx ring for this descriptor
- * @qw: the descriptor data
+ * @rx_desc: the Rx descriptor for programming Status, not a packet descriptor.
  * @prog_id: the id originally used for programming
  *
  * This is used to verify if the FD programming or invalidation
  * requested by SW to the HW is successful or not and take actions accordingly.
  **/
-static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u32 qw, u8 prog_id)
+static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
+                                 union i40e_rx_desc *rx_desc, u8 prog_id)
 {
-       struct pci_dev *pdev = rx_ring->vsi->back->pdev;
+       struct i40e_pf *pf = rx_ring->vsi->back;
+       struct pci_dev *pdev = pf->pdev;
+       u32 fcnt_prog, fcnt_avail;
        u32 error;
+       u64 qw;
 
+       qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
        error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >>
                I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT;
 
-       /* for now just print the Status */
-       dev_info(&pdev->dev, "FD programming id %02x, Status %08x\n",
-                prog_id, error);
+       if (error == (0x1 << I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) {
+               dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n",
+                        rx_desc->wb.qword0.hi_dword.fd_id);
+
+               /* filter programming failed most likely due to table full */
+               fcnt_prog = i40e_get_current_fd_count(pf);
+               fcnt_avail = pf->hw.fdir_shared_filter_count +
+                                                      pf->fdir_pf_filter_count;
+
+               /* If ATR is running fcnt_prog can quickly change,
+                * if we are very close to full, it makes sense to disable
+                * FD ATR/SB and then re-enable it when there is room.
+                */
+               if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) {
+                       /* Turn off ATR first */
+                       if (pf->flags | I40E_FLAG_FD_ATR_ENABLED) {
+                               pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                               dev_warn(&pdev->dev, "FD filter space full, ATR for further flows will be turned off\n");
+                               pf->auto_disable_flags |=
+                                                      I40E_FLAG_FD_ATR_ENABLED;
+                               pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
+                       } else if (pf->flags | I40E_FLAG_FD_SB_ENABLED) {
+                               pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+                               dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
+                               pf->auto_disable_flags |=
+                                                       I40E_FLAG_FD_SB_ENABLED;
+                               pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
+                       }
+               } else {
+                       dev_info(&pdev->dev, "FD filter programming error");
+               }
+       } else if (error ==
+                         (0x1 << I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) {
+               netdev_info(rx_ring->vsi->netdev, "ntuple filter loc = %d, could not be removed\n",
+                           rx_desc->wb.qword0.hi_dword.fd_id);
+       }
 }
 
 /**
@@ -577,7 +881,7 @@ static void i40e_clean_programming_status(struct i40e_ring *rx_ring,
                  I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT;
 
        if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS)
-               i40e_fd_handle_status(rx_ring, qw, id);
+               i40e_fd_handle_status(rx_ring, rx_desc, id);
 }
 
 /**
@@ -955,6 +1259,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring,
                return 0;
 }
 
+/**
+ * i40e_ptype_to_hash - get a hash type
+ * @ptype: the ptype value from the descriptor
+ *
+ * Returns a hash type to be used by skb_set_hash
+ **/
+static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+{
+       struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
+
+       if (!decoded.known)
+               return PKT_HASH_TYPE_NONE;
+
+       if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+           decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4)
+               return PKT_HASH_TYPE_L4;
+       else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+                decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3)
+               return PKT_HASH_TYPE_L3;
+       else
+               return PKT_HASH_TYPE_L2;
+}
+
 /**
  * i40e_clean_rx_irq - Reclaim resources after receive completes
  * @rx_ring:  rx ring to clean
@@ -972,8 +1299,11 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        u16 i = rx_ring->next_to_clean;
        union i40e_rx_desc *rx_desc;
        u32 rx_error, rx_status;
+       u8 rx_ptype;
        u64 qword;
-       u16 rx_ptype;
+
+       if (budget <= 0)
+               return 0;
 
        rx_desc = I40E_RX_DESC(rx_ring, i);
        qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
@@ -1087,7 +1417,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                        goto next_desc;
                }
 
-               skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
+               skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
+                            i40e_ptype_to_hash(rx_ptype));
                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) >>
@@ -1246,8 +1577,6 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (!tx_ring->atr_sample_rate)
                return;
 
-       tx_ring->atr_count++;
-
        /* snag network header to get L4 type and address */
        hdr.network = skb_network_header(skb);
 
@@ -1269,6 +1598,12 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
 
        th = (struct tcphdr *)(hdr.network + hlen);
 
+       /* Due to lack of space, no more new filters can be programmed */
+       if (th->syn && (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
+               return;
+
+       tx_ring->atr_count++;
+
        /* sample on all syn/fin packets or once every atr sample rate */
        if (!th->fin && !th->syn && (tx_ring->atr_count < tx_ring->atr_sample_rate))
                return;
@@ -1812,7 +2147,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
 
        /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
         *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
-        *       + 2 desc gap to keep tail from touching head,
+        *       + 4 desc gap to avoid the cache line where head is,
         *       + 1 desc for context descriptor,
         * otherwise try next time
         */
@@ -1823,7 +2158,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
        count += skb_shinfo(skb)->nr_frags;
 #endif
        count += TXD_USE_COUNT(skb_headlen(skb));
-       if (i40e_maybe_stop_tx(tx_ring, count + 3)) {
+       if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
                tx_ring->tx_stats.tx_busy++;
                return 0;
        }
index 181a825d3160dc377d4b909821a15959b3c49fe2..5c902f448b1dcc3790a089298c9107d88d3ace92 100644 (file)
@@ -458,6 +458,10 @@ union i40e_32byte_rx_desc {
                        union {
                                __le32 rss; /* RSS Hash */
                                __le32 fcoe_param; /* FCoE DDP Context id */
+                               /* Flow director filter id in case of
+                                * Programming status desc WB
+                                */
+                               __le32 fd_id;
                        } hi_dword;
                } qword0;
                struct {
@@ -698,7 +702,7 @@ enum i40e_rx_prog_status_desc_prog_id_masks {
 enum i40e_rx_prog_status_desc_error_bits {
        /* Note: These are predefined bit offsets */
        I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT      = 0,
-       I40E_RX_PROG_STATUS_DESC_NO_FD_QUOTA_SHIFT      = 1,
+       I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT      = 1,
        I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT    = 2,
        I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT    = 3
 };
index 189e250198dd698f83d2ca8a9f188eb38c0ba970..7839343b967b069fd554275a8e110623ef741d93 100644 (file)
@@ -69,7 +69,7 @@ static inline bool i40e_vc_isvalid_vector_id(struct i40e_vf *vf, u8 vector_id)
 {
        struct i40e_pf *pf = vf->pf;
 
-       return vector_id <= pf->hw.func_caps.num_msix_vectors_vf;
+       return vector_id < pf->hw.func_caps.num_msix_vectors_vf;
 }
 
 /***********************vf resource mgmt routines*****************/
@@ -126,8 +126,8 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_idx,
                reg_idx = I40E_VPINT_LNKLST0(vf->vf_id);
        else
                reg_idx = I40E_VPINT_LNKLSTN(
-                                          (pf->hw.func_caps.num_msix_vectors_vf
-                                             * vf->vf_id) + (vector_id - 1));
+                    ((pf->hw.func_caps.num_msix_vectors_vf - 1) * vf->vf_id) +
+                    (vector_id - 1));
 
        if (vecmap->rxq_map == 0 && vecmap->txq_map == 0) {
                /* Special case - No queues mapped on this vector */
@@ -506,7 +506,8 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
                vf->lan_vsi_index = 0;
                vf->lan_vsi_id = 0;
        }
-       msix_vf = pf->hw.func_caps.num_msix_vectors_vf + 1;
+       msix_vf = pf->hw.func_caps.num_msix_vectors_vf;
+
        /* disable interrupts so the VF starts in a known state */
        for (i = 0; i < msix_vf; i++) {
                /* format is same for both registers */
@@ -858,7 +859,7 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
                }
        }
        /* allocate memory */
-       vfs = kzalloc(num_alloc_vfs * sizeof(struct i40e_vf), GFP_KERNEL);
+       vfs = kcalloc(num_alloc_vfs, sizeof(struct i40e_vf), GFP_KERNEL);
        if (!vfs) {
                ret = -ENOMEM;
                goto err_alloc;
index 7b13953b28c47a34af943a684b376dcb1d3ebf15..c688a0fc5c2965a2ddf42d935b1fabd6902ace23 100644 (file)
@@ -160,6 +160,372 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw,
 }
 
 
+/* The i40evf_ptype_lookup table is used to convert from the 8-bit ptype in the
+ * hardware to a bit-field that can be used by SW to more easily determine the
+ * packet type.
+ *
+ * Macros are used to shorten the table lines and make this table human
+ * readable.
+ *
+ * We store the PTYPE in the top byte of the bit field - this is just so that
+ * we can check that the table doesn't have a row missing, as the index into
+ * the table should be the PTYPE.
+ *
+ * Typical work flow:
+ *
+ * IF NOT i40evf_ptype_lookup[ptype].known
+ * THEN
+ *      Packet is unknown
+ * ELSE IF i40evf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP
+ *      Use the rest of the fields to look at the tunnels, inner protocols, etc
+ * ELSE
+ *      Use the enum i40e_rx_l2_ptype to decode the packet type
+ * ENDIF
+ */
+
+/* macro to make the table lines short */
+#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
+       {       PTYPE, \
+               1, \
+               I40E_RX_PTYPE_OUTER_##OUTER_IP, \
+               I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \
+               I40E_RX_PTYPE_##OUTER_FRAG, \
+               I40E_RX_PTYPE_TUNNEL_##T, \
+               I40E_RX_PTYPE_TUNNEL_END_##TE, \
+               I40E_RX_PTYPE_##TEF, \
+               I40E_RX_PTYPE_INNER_PROT_##I, \
+               I40E_RX_PTYPE_PAYLOAD_LAYER_##PL }
+
+#define I40E_PTT_UNUSED_ENTRY(PTYPE) \
+               { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+
+/* shorter macros makes the table fit but are terse */
+#define I40E_RX_PTYPE_NOF              I40E_RX_PTYPE_NOT_FRAG
+#define I40E_RX_PTYPE_FRG              I40E_RX_PTYPE_FRAG
+#define I40E_RX_PTYPE_INNER_PROT_TS    I40E_RX_PTYPE_INNER_PROT_TIMESYNC
+
+/* Lookup table mapping the HW PTYPE to the bit field for decoding */
+struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = {
+       /* L2 Packet types */
+       I40E_PTT_UNUSED_ENTRY(0),
+       I40E_PTT(1,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(2,  L2, NONE, NOF, NONE, NONE, NOF, TS,   PAY2),
+       I40E_PTT(3,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT_UNUSED_ENTRY(4),
+       I40E_PTT_UNUSED_ENTRY(5),
+       I40E_PTT(6,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(7,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT_UNUSED_ENTRY(8),
+       I40E_PTT_UNUSED_ENTRY(9),
+       I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
+       I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+
+       /* Non Tunneled IPv4 */
+       I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(25),
+       I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP,  PAY4),
+       I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4),
+       I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+       /* IPv4 --> IPv4 */
+       I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(32),
+       I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> IPv6 */
+       I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(39),
+       I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT */
+       I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 --> GRE/NAT --> IPv4 */
+       I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(47),
+       I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> IPv6 */
+       I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(54),
+       I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> MAC */
+       I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 --> GRE/NAT --> MAC --> IPv4 */
+       I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(62),
+       I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT -> MAC --> IPv6 */
+       I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(69),
+       I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> MAC/VLAN */
+       I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */
+       I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(77),
+       I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */
+       I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(84),
+       I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+       /* Non Tunneled IPv6 */
+       I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP,  PAY3),
+       I40E_PTT_UNUSED_ENTRY(91),
+       I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP,  PAY4),
+       I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
+       I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+       /* IPv6 --> IPv4 */
+       I40E_PTT(95,  IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(96,  IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(97,  IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(98),
+       I40E_PTT(99,  IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> IPv6 */
+       I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(105),
+       I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT */
+       I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> IPv4 */
+       I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(113),
+       I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> IPv6 */
+       I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(120),
+       I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC */
+       I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> MAC -> IPv4 */
+       I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(128),
+       I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC -> IPv6 */
+       I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(135),
+       I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN */
+       I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */
+       I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(143),
+       I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */
+       I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(150),
+       I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+       /* unused entries */
+       I40E_PTT_UNUSED_ENTRY(154),
+       I40E_PTT_UNUSED_ENTRY(155),
+       I40E_PTT_UNUSED_ENTRY(156),
+       I40E_PTT_UNUSED_ENTRY(157),
+       I40E_PTT_UNUSED_ENTRY(158),
+       I40E_PTT_UNUSED_ENTRY(159),
+
+       I40E_PTT_UNUSED_ENTRY(160),
+       I40E_PTT_UNUSED_ENTRY(161),
+       I40E_PTT_UNUSED_ENTRY(162),
+       I40E_PTT_UNUSED_ENTRY(163),
+       I40E_PTT_UNUSED_ENTRY(164),
+       I40E_PTT_UNUSED_ENTRY(165),
+       I40E_PTT_UNUSED_ENTRY(166),
+       I40E_PTT_UNUSED_ENTRY(167),
+       I40E_PTT_UNUSED_ENTRY(168),
+       I40E_PTT_UNUSED_ENTRY(169),
+
+       I40E_PTT_UNUSED_ENTRY(170),
+       I40E_PTT_UNUSED_ENTRY(171),
+       I40E_PTT_UNUSED_ENTRY(172),
+       I40E_PTT_UNUSED_ENTRY(173),
+       I40E_PTT_UNUSED_ENTRY(174),
+       I40E_PTT_UNUSED_ENTRY(175),
+       I40E_PTT_UNUSED_ENTRY(176),
+       I40E_PTT_UNUSED_ENTRY(177),
+       I40E_PTT_UNUSED_ENTRY(178),
+       I40E_PTT_UNUSED_ENTRY(179),
+
+       I40E_PTT_UNUSED_ENTRY(180),
+       I40E_PTT_UNUSED_ENTRY(181),
+       I40E_PTT_UNUSED_ENTRY(182),
+       I40E_PTT_UNUSED_ENTRY(183),
+       I40E_PTT_UNUSED_ENTRY(184),
+       I40E_PTT_UNUSED_ENTRY(185),
+       I40E_PTT_UNUSED_ENTRY(186),
+       I40E_PTT_UNUSED_ENTRY(187),
+       I40E_PTT_UNUSED_ENTRY(188),
+       I40E_PTT_UNUSED_ENTRY(189),
+
+       I40E_PTT_UNUSED_ENTRY(190),
+       I40E_PTT_UNUSED_ENTRY(191),
+       I40E_PTT_UNUSED_ENTRY(192),
+       I40E_PTT_UNUSED_ENTRY(193),
+       I40E_PTT_UNUSED_ENTRY(194),
+       I40E_PTT_UNUSED_ENTRY(195),
+       I40E_PTT_UNUSED_ENTRY(196),
+       I40E_PTT_UNUSED_ENTRY(197),
+       I40E_PTT_UNUSED_ENTRY(198),
+       I40E_PTT_UNUSED_ENTRY(199),
+
+       I40E_PTT_UNUSED_ENTRY(200),
+       I40E_PTT_UNUSED_ENTRY(201),
+       I40E_PTT_UNUSED_ENTRY(202),
+       I40E_PTT_UNUSED_ENTRY(203),
+       I40E_PTT_UNUSED_ENTRY(204),
+       I40E_PTT_UNUSED_ENTRY(205),
+       I40E_PTT_UNUSED_ENTRY(206),
+       I40E_PTT_UNUSED_ENTRY(207),
+       I40E_PTT_UNUSED_ENTRY(208),
+       I40E_PTT_UNUSED_ENTRY(209),
+
+       I40E_PTT_UNUSED_ENTRY(210),
+       I40E_PTT_UNUSED_ENTRY(211),
+       I40E_PTT_UNUSED_ENTRY(212),
+       I40E_PTT_UNUSED_ENTRY(213),
+       I40E_PTT_UNUSED_ENTRY(214),
+       I40E_PTT_UNUSED_ENTRY(215),
+       I40E_PTT_UNUSED_ENTRY(216),
+       I40E_PTT_UNUSED_ENTRY(217),
+       I40E_PTT_UNUSED_ENTRY(218),
+       I40E_PTT_UNUSED_ENTRY(219),
+
+       I40E_PTT_UNUSED_ENTRY(220),
+       I40E_PTT_UNUSED_ENTRY(221),
+       I40E_PTT_UNUSED_ENTRY(222),
+       I40E_PTT_UNUSED_ENTRY(223),
+       I40E_PTT_UNUSED_ENTRY(224),
+       I40E_PTT_UNUSED_ENTRY(225),
+       I40E_PTT_UNUSED_ENTRY(226),
+       I40E_PTT_UNUSED_ENTRY(227),
+       I40E_PTT_UNUSED_ENTRY(228),
+       I40E_PTT_UNUSED_ENTRY(229),
+
+       I40E_PTT_UNUSED_ENTRY(230),
+       I40E_PTT_UNUSED_ENTRY(231),
+       I40E_PTT_UNUSED_ENTRY(232),
+       I40E_PTT_UNUSED_ENTRY(233),
+       I40E_PTT_UNUSED_ENTRY(234),
+       I40E_PTT_UNUSED_ENTRY(235),
+       I40E_PTT_UNUSED_ENTRY(236),
+       I40E_PTT_UNUSED_ENTRY(237),
+       I40E_PTT_UNUSED_ENTRY(238),
+       I40E_PTT_UNUSED_ENTRY(239),
+
+       I40E_PTT_UNUSED_ENTRY(240),
+       I40E_PTT_UNUSED_ENTRY(241),
+       I40E_PTT_UNUSED_ENTRY(242),
+       I40E_PTT_UNUSED_ENTRY(243),
+       I40E_PTT_UNUSED_ENTRY(244),
+       I40E_PTT_UNUSED_ENTRY(245),
+       I40E_PTT_UNUSED_ENTRY(246),
+       I40E_PTT_UNUSED_ENTRY(247),
+       I40E_PTT_UNUSED_ENTRY(248),
+       I40E_PTT_UNUSED_ENTRY(249),
+
+       I40E_PTT_UNUSED_ENTRY(250),
+       I40E_PTT_UNUSED_ENTRY(251),
+       I40E_PTT_UNUSED_ENTRY(252),
+       I40E_PTT_UNUSED_ENTRY(253),
+       I40E_PTT_UNUSED_ENTRY(254),
+       I40E_PTT_UNUSED_ENTRY(255)
+};
+
+
 /**
  * i40e_aq_send_msg_to_pf
  * @hw: pointer to the hardware structure
index 7841573a58c943304af1aa671699af1756fb61ea..862fcdf52675dabb0ea7372f971c49490db29c1a 100644 (file)
@@ -63,6 +63,13 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw,
 
 i40e_status i40e_set_mac_type(struct i40e_hw *hw);
 
+extern struct i40e_rx_ptype_decoded i40evf_ptype_lookup[];
+
+static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
+{
+       return  i40evf_ptype_lookup[ptype];
+}
+
 /* prototype for functions used for SW locks */
 
 /* i40e_common for VF drivers*/
index 827bb5fa4af959ee3614f3873a26ccaec0c978e9..b1d87c6a5c35c1a55b07701c549f692d3b4126f2 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/prefetch.h>
 
 #include "i40evf.h"
+#include "i40e_prototype.h"
 
 static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
                                u32 td_tag)
@@ -785,6 +786,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring,
                return 0;
 }
 
+/**
+ * i40e_ptype_to_hash - get a hash type
+ * @ptype: the ptype value from the descriptor
+ *
+ * Returns a hash type to be used by skb_set_hash
+ **/
+static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+{
+       struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
+
+       if (!decoded.known)
+               return PKT_HASH_TYPE_NONE;
+
+       if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+           decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4)
+               return PKT_HASH_TYPE_L4;
+       else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+                decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3)
+               return PKT_HASH_TYPE_L3;
+       else
+               return PKT_HASH_TYPE_L2;
+}
+
 /**
  * i40e_clean_rx_irq - Reclaim resources after receive completes
  * @rx_ring:  rx ring to clean
@@ -802,8 +826,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        u16 i = rx_ring->next_to_clean;
        union i40e_rx_desc *rx_desc;
        u32 rx_error, rx_status;
+       u8 rx_ptype;
        u64 qword;
-       u16 rx_ptype;
 
        rx_desc = I40E_RX_DESC(rx_ring, i);
        qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
@@ -912,7 +936,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                        goto next_desc;
                }
 
-               skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
+               skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
+                            i40e_ptype_to_hash(rx_ptype));
                /* probably a little skewed due to removing CRC */
                total_rx_bytes += skb->len;
                total_rx_packets++;
@@ -1457,7 +1482,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
 
        /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
         *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
-        *       + 2 desc gap to keep tail from touching head,
+        *       + 4 desc gap to avoid the cache line where head is,
         *       + 1 desc for context descriptor,
         * otherwise try next time
         */
@@ -1468,7 +1493,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
        count += skb_shinfo(skb)->nr_frags;
 #endif
        count += TXD_USE_COUNT(skb_headlen(skb));
-       if (i40e_maybe_stop_tx(tx_ring, count + 3)) {
+       if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
                tx_ring->tx_stats.tx_busy++;
                return 0;
        }
index 092aace2a76cfd93c576266b5af836f3736b79c0..7189d6f08ddd2fd7374e747abb5f6cc319ad0ec1 100644 (file)
@@ -464,6 +464,10 @@ union i40e_32byte_rx_desc {
                        union {
                                __le32 rss; /* RSS Hash */
                                __le32 fcoe_param; /* FCoE DDP Context id */
+                               /* Flow director filter id in case of
+                                * Programming status desc WB
+                                */
+                               __le32 fd_id;
                        } hi_dword;
                } qword0;
                struct {
@@ -704,7 +708,7 @@ enum i40e_rx_prog_status_desc_prog_id_masks {
 enum i40e_rx_prog_status_desc_error_bits {
        /* Note: These are predefined bit offsets */
        I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT      = 0,
-       I40E_RX_PROG_STATUS_DESC_NO_FD_QUOTA_SHIFT      = 1,
+       I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT      = 1,
        I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT    = 2,
        I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT    = 3
 };
index b2c03bca79295253a5bdfbb9872b79e5787c0871..d62e27f6e83a7b3d3ec60568a68bd57146654572 100644 (file)
@@ -31,7 +31,7 @@ char i40evf_driver_name[] = "i40evf";
 static const char i40evf_driver_string[] =
        "Intel(R) XL710 X710 Virtual Function Network Driver";
 
-#define DRV_VERSION "0.9.13"
+#define DRV_VERSION "0.9.14"
 const char i40evf_driver_version[] = DRV_VERSION;
 static const char i40evf_copyright[] =
        "Copyright (c) 2013 - 2014 Intel Corporation.";
@@ -1141,7 +1141,7 @@ static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter)
         * (roughly) twice the number of vectors as there are CPU's.
         */
        v_budget = min(pairs, (int)(num_online_cpus() * 2)) + NONQ_VECS;
-       v_budget = min(v_budget, (int)adapter->vf_res->max_vectors + 1);
+       v_budget = min(v_budget, (int)adapter->vf_res->max_vectors);
 
        /* A failure in MSI-X entry allocation isn't fatal, but it does
         * mean we disable MSI-X capabilities of the adapter.
@@ -2036,6 +2036,7 @@ static void i40evf_init_task(struct work_struct *work)
                            NETIF_F_IPV6_CSUM |
                            NETIF_F_TSO |
                            NETIF_F_TSO6 |
+                           NETIF_F_RXCSUM |
                            NETIF_F_GRO;
 
        if (adapter->vf_res->vf_offload_flags
@@ -2046,6 +2047,10 @@ static void i40evf_init_task(struct work_struct *work)
                                    NETIF_F_HW_VLAN_CTAG_FILTER;
        }
 
+       /* copy netdev features into list of user selectable features */
+       netdev->hw_features |= netdev->features;
+       netdev->hw_features &= ~NETIF_F_RXCSUM;
+
        if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
                dev_info(&pdev->dev, "Invalid MAC address %pMAC, using random\n",
                         adapter->hw.mac.addr);
@@ -2177,17 +2182,12 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err)
                return err;
 
-       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
-               /* coherent mask for the same size will always succeed if
-                * dma_set_mask does
-                */
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
-       } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-       } else {
-               dev_err(&pdev->dev, "%s: DMA configuration failed: %d\n",
-                        __func__, err);
-               err = -EIO;
+       err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+       if (err)
+               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (err) {
+               dev_err(&pdev->dev,
+                       "DMA configuration failed: 0x%x\n", err);
                goto err_dma;
        }
 
index 45947b3f7d922ff0c1f9097cf03f7c573c78c50e..fa36fe12e77502658cfe864780849d6f00e93c2e 100644 (file)
@@ -76,8 +76,6 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw);
 static const u16 e1000_82580_rxpbs_table[] =
        { 36, 72, 144, 1, 2, 4, 8, 16,
          35, 70, 140 };
-#define E1000_82580_RXPBS_TABLE_SIZE \
-       (sizeof(e1000_82580_rxpbs_table)/sizeof(u16))
 
 /**
  *  igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
@@ -2307,7 +2305,7 @@ u16 igb_rxpbs_adjust_82580(u32 data)
 {
        u16 ret_val = 0;
 
-       if (data < E1000_82580_RXPBS_TABLE_SIZE)
+       if (data < ARRAY_SIZE(e1000_82580_rxpbs_table))
                ret_val = e1000_82580_rxpbs_table[data];
 
        return ret_val;
@@ -2713,6 +2711,7 @@ static const u8 e1000_emc_therm_limit[4] = {
        E1000_EMC_DIODE3_THERM_LIMIT
 };
 
+#ifdef CONFIG_IGB_HWMON
 /**
  *  igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
  *  @hw: pointer to hardware structure
@@ -2835,6 +2834,7 @@ static s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
        return status;
 }
 
+#endif
 static struct e1000_mac_operations e1000_mac_ops_82575 = {
        .init_hw              = igb_init_hw_82575,
        .check_for_link       = igb_check_for_link_82575,
index f12b086e578d41e09815cf467cab2190a9647136..2a721a15afc16dd83bf829c9faf8bf94fc394824 100644 (file)
@@ -265,6 +265,7 @@ u16 igb_rxpbs_adjust_82580(u32 data);
 s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data);
 s32 igb_set_eee_i350(struct e1000_hw *);
 s32 igb_set_eee_i354(struct e1000_hw *);
+s32 igb_get_eee_status_i354(struct e1000_hw *hw, bool *status);
 
 #define E1000_I2C_THERMAL_SENSOR_ADDR  0xF8
 #define E1000_EMC_INTERNAL_DATA                0x00
index fc3fc2c6fe404161c6d1616348ae679a7afe54b7..a202c9640e93a32d60dd25eb0619361564768070 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/pci.h>
+#include <linux/mdio.h>
 
 struct igb_adapter;
 
@@ -455,6 +456,7 @@ struct igb_adapter {
        unsigned long link_check_timeout;
        int copper_tries;
        struct e1000_info ei;
+       u16 eee_advert;
 };
 
 #define IGB_FLAG_HAS_MSI               (1 << 0)
@@ -471,6 +473,7 @@ struct igb_adapter {
 #define IGB_FLAG_MAS_CAPABLE           (1 << 11)
 #define IGB_FLAG_MAS_ENABLE            (1 << 12)
 #define IGB_FLAG_HAS_MSIX              (1 << 13)
+#define IGB_FLAG_EEE                   (1 << 14)
 
 /* Media Auto Sense */
 #define IGB_MAS_ENABLE_0               0X0001
index c7f574165298faab4b7cd7fc4a7021e1709b6fc4..e35bc1faa452ca9e0200b1227617459b9f99a448 100644 (file)
@@ -2273,15 +2273,15 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
 
                ring = adapter->tx_ring[j];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->tx_syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
                        data[i]   = ring->tx_stats.packets;
                        data[i+1] = ring->tx_stats.bytes;
                        data[i+2] = ring->tx_stats.restart_queue;
-               } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->tx_syncp2);
+                       start = u64_stats_fetch_begin_irq(&ring->tx_syncp2);
                        restart2  = ring->tx_stats.restart_queue2;
-               } while (u64_stats_fetch_retry_bh(&ring->tx_syncp2, start));
+               } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start));
                data[i+2] += restart2;
 
                i += IGB_TX_QUEUE_STATS_LEN;
@@ -2289,13 +2289,13 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
        for (j = 0; j < adapter->num_rx_queues; j++) {
                ring = adapter->rx_ring[j];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
                        data[i]   = ring->rx_stats.packets;
                        data[i+1] = ring->rx_stats.bytes;
                        data[i+2] = ring->rx_stats.drops;
                        data[i+3] = ring->rx_stats.csum_err;
                        data[i+4] = ring->rx_stats.alloc_failed;
-               } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
                i += IGB_RX_QUEUE_STATS_LEN;
        }
        spin_unlock(&adapter->stats64_lock);
@@ -2587,7 +2587,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       u32 ipcnfg, eeer, ret_val;
+       u32 ret_val;
        u16 phy_data;
 
        if ((hw->mac.type < e1000_i350) ||
@@ -2596,16 +2596,25 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
 
        edata->supported = (SUPPORTED_1000baseT_Full |
                            SUPPORTED_100baseT_Full);
+       if (!hw->dev_spec._82575.eee_disable)
+               edata->advertised =
+                       mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert);
 
-       ipcnfg = rd32(E1000_IPCNFG);
-       eeer = rd32(E1000_EEER);
+       /* The IPCNFG and EEER registers are not supported on I354. */
+       if (hw->mac.type == e1000_i354) {
+               igb_get_eee_status_i354(hw, (bool *)&edata->eee_active);
+       } else {
+               u32 eeer;
+
+               eeer = rd32(E1000_EEER);
 
-       /* EEE status on negotiated link */
-       if (ipcnfg & E1000_IPCNFG_EEE_1G_AN)
-               edata->advertised = ADVERTISED_1000baseT_Full;
+               /* EEE status on negotiated link */
+               if (eeer & E1000_EEER_EEE_NEG)
+                       edata->eee_active = true;
 
-       if (ipcnfg & E1000_IPCNFG_EEE_100M_AN)
-               edata->advertised |= ADVERTISED_100baseT_Full;
+               if (eeer & E1000_EEER_TX_LPI_EN)
+                       edata->tx_lpi_enabled = true;
+       }
 
        /* EEE Link Partner Advertised */
        switch (hw->mac.type) {
@@ -2616,8 +2625,8 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
                        return -ENODATA;
 
                edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
-
                break;
+       case e1000_i354:
        case e1000_i210:
        case e1000_i211:
                ret_val = igb_read_xmdio_reg(hw, E1000_EEE_LP_ADV_ADDR_I210,
@@ -2633,12 +2642,10 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
                break;
        }
 
-       if (eeer & E1000_EEER_EEE_NEG)
-               edata->eee_active = true;
-
        edata->eee_enabled = !hw->dev_spec._82575.eee_disable;
 
-       if (eeer & E1000_EEER_TX_LPI_EN)
+       if ((hw->mac.type == e1000_i354) &&
+           (edata->eee_enabled))
                edata->tx_lpi_enabled = true;
 
        /* Report correct negotiated EEE status for devices that
@@ -2686,9 +2693,10 @@ static int igb_set_eee(struct net_device *netdev,
                        return -EINVAL;
                }
 
-               if (eee_curr.advertised != edata->advertised) {
+               if (edata->advertised &
+                   ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) {
                        dev_err(&adapter->pdev->dev,
-                               "Setting EEE Advertisement is not supported\n");
+                               "EEE Advertisement supports only 100Tx and or 100T full duplex\n");
                        return -EINVAL;
                }
 
@@ -2698,9 +2706,14 @@ static int igb_set_eee(struct net_device *netdev,
                        return -EINVAL;
                }
 
+       adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
        if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {
                hw->dev_spec._82575.eee_disable = !edata->eee_enabled;
-               igb_set_eee_i350(hw);
+               adapter->flags |= IGB_FLAG_EEE;
+               if (hw->mac.type == e1000_i350)
+                       igb_set_eee_i350(hw);
+               else
+                       igb_set_eee_i354(hw);
 
                /* reset link */
                if (netif_running(netdev))
index 3384156cf1b504e6e15e36583c3a7bc756e0001b..ac06492fb8163c950d476c0980b108f990b08ee4 100644 (file)
@@ -1726,6 +1726,10 @@ int igb_up(struct igb_adapter *adapter)
        hw->mac.get_link_status = 1;
        schedule_work(&adapter->watchdog_task);
 
+       if ((adapter->flags & IGB_FLAG_EEE) &&
+           (!hw->dev_spec._82575.eee_disable))
+               adapter->eee_advert = MDIO_EEE_100TX | MDIO_EEE_1000T;
+
        return 0;
 }
 
@@ -1974,6 +1978,21 @@ void igb_reset(struct igb_adapter *adapter)
                }
        }
 #endif
+       /* Re-establish EEE setting */
+       if (hw->phy.media_type == e1000_media_type_copper) {
+               switch (mac->type) {
+               case e1000_i350:
+               case e1000_i210:
+               case e1000_i211:
+                       igb_set_eee_i350(hw);
+                       break;
+               case e1000_i354:
+                       igb_set_eee_i354(hw);
+                       break;
+               default:
+                       break;
+               }
+       }
        if (!netif_running(adapter->netdev))
                igb_power_down_link(adapter);
 
@@ -2560,23 +2579,36 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                (adapter->flags & IGB_FLAG_HAS_MSIX) ? "MSI-X" :
                (adapter->flags & IGB_FLAG_HAS_MSI) ? "MSI" : "legacy",
                adapter->num_rx_queues, adapter->num_tx_queues);
-       switch (hw->mac.type) {
-       case e1000_i350:
-       case e1000_i210:
-       case e1000_i211:
-               igb_set_eee_i350(hw);
-               break;
-       case e1000_i354:
-               if (hw->phy.media_type == e1000_media_type_copper) {
+       if (hw->phy.media_type == e1000_media_type_copper) {
+               switch (hw->mac.type) {
+               case e1000_i350:
+               case e1000_i210:
+               case e1000_i211:
+                       /* Enable EEE for internal copper PHY devices */
+                       err = igb_set_eee_i350(hw);
+                       if ((!err) &&
+                           (!hw->dev_spec._82575.eee_disable)) {
+                               adapter->eee_advert =
+                                       MDIO_EEE_100TX | MDIO_EEE_1000T;
+                               adapter->flags |= IGB_FLAG_EEE;
+                       }
+                       break;
+               case e1000_i354:
                        if ((rd32(E1000_CTRL_EXT) &
-                           E1000_CTRL_EXT_LINK_MODE_SGMII))
-                               igb_set_eee_i354(hw);
+                           E1000_CTRL_EXT_LINK_MODE_SGMII)) {
+                               err = igb_set_eee_i354(hw);
+                               if ((!err) &&
+                                       (!hw->dev_spec._82575.eee_disable)) {
+                                       adapter->eee_advert =
+                                          MDIO_EEE_100TX | MDIO_EEE_1000T;
+                                       adapter->flags |= IGB_FLAG_EEE;
+                               }
+                       }
+                       break;
+               default:
+                       break;
                }
-               break;
-       default:
-               break;
        }
-
        pm_runtime_put_noidle(&pdev->dev);
        return 0;
 
@@ -4158,6 +4190,15 @@ static void igb_watchdog_task(struct work_struct *work)
                               (ctrl & E1000_CTRL_RFCE) ?  "RX" :
                               (ctrl & E1000_CTRL_TFCE) ?  "TX" : "None");
 
+                       /* disable EEE if enabled */
+                       if ((adapter->flags & IGB_FLAG_EEE) &&
+                               (adapter->link_duplex == HALF_DUPLEX)) {
+                               dev_info(&adapter->pdev->dev,
+                               "EEE Disabled: unsupported at half duplex. Re-enable using ethtool when at full duplex.\n");
+                               adapter->hw.dev_spec._82575.eee_disable = true;
+                               adapter->flags &= ~IGB_FLAG_EEE;
+                       }
+
                        /* check if SmartSpeed worked */
                        igb_check_downshift(hw);
                        if (phy->speed_downgraded)
@@ -4306,8 +4347,7 @@ enum latency_range {
  *  were determined based on theoretical maximum wire speed and testing
  *  data, in order to minimize response time while increasing bulk
  *  throughput.
- *  This functionality is controlled by the InterruptThrottleRate module
- *  parameter (see igb_param.c)
+ *  This functionality is controlled by ethtool's coalescing settings.
  *  NOTE:  This function is called only when operating in a multiqueue
  *         receive environment.
  **/
@@ -4381,8 +4421,7 @@ clear_counts:
  *  based on theoretical maximum wire speed and thresholds were set based
  *  on testing data as well as attempting to minimize response time
  *  while increasing bulk throughput.
- *  this functionality is controlled by the InterruptThrottleRate module
- *  parameter (see igb_param.c)
+ *  This functionality is controlled by ethtool's coalescing settings.
  *  NOTE:  These calculations are only valid when operating in a single-
  *         queue environment.
  **/
@@ -5127,10 +5166,10 @@ void igb_update_stats(struct igb_adapter *adapter,
                }
 
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
                        _bytes = ring->rx_stats.bytes;
                        _packets = ring->rx_stats.packets;
-               } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
                bytes += _bytes;
                packets += _packets;
        }
@@ -5143,10 +5182,10 @@ void igb_update_stats(struct igb_adapter *adapter,
        for (i = 0; i < adapter->num_tx_queues; i++) {
                struct igb_ring *ring = adapter->tx_ring[i];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->tx_syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
                        _bytes = ring->tx_stats.bytes;
                        _packets = ring->tx_stats.packets;
-               } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
                bytes += _bytes;
                packets += _packets;
        }
@@ -6620,7 +6659,9 @@ static inline void igb_rx_hash(struct igb_ring *ring,
                               struct sk_buff *skb)
 {
        if (ring->netdev->features & NETIF_F_RXHASH)
-               skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+               skb_set_hash(skb,
+                            le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+                            PKT_HASH_TYPE_L3);
 }
 
 /**
@@ -6903,7 +6944,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
        unsigned int total_bytes = 0, total_packets = 0;
        u16 cleaned_count = igb_desc_unused(rx_ring);
 
-       do {
+       while (likely(total_packets < budget)) {
                union e1000_adv_rx_desc *rx_desc;
 
                /* return some buffers to hardware, one at a time is too slow */
@@ -6955,7 +6996,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
 
                /* update budget accounting */
                total_packets++;
-       } while (likely(total_packets < budget));
+       }
 
        /* place incomplete frames back on ring for completion */
        rx_ring->skb = skb;
index 57e390cbe6d0d21630f6bf6904a0c8a663601931..f42c201f727fc7fdb46062808cd0435927081256 100644 (file)
@@ -1521,12 +1521,12 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        int tso;
 
        if (test_bit(__IXGB_DOWN, &adapter->flags)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
        if (skb->len <= 0) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -1543,7 +1543,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        tso = ixgb_tso(adapter, skb);
        if (tso < 0) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
index 4371ef0ed4a0b5608d3b5731bab19bffbc28770b..2fff0fc4e6e8a0b76a1ed880da906d08397c7ed2 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 15506f0780b20e9107915f980b60e92d5acc380c..f8ebe583a2abfb6bca5a147b7a463dc675980cdf 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -104,6 +105,7 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
        mac->mcft_size = IXGBE_82598_MC_TBL_SIZE;
        mac->vft_size = IXGBE_82598_VFT_TBL_SIZE;
        mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES;
+       mac->rx_pb_size = IXGBE_82598_RX_PB_SIZE;
        mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES;
        mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES;
        mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
@@ -205,8 +207,6 @@ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw)
                IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval);
        }
 
-       hw->mac.rx_pb_size = IXGBE_82598_RX_PB_SIZE;
-
        /* set the completion timeout for interface */
        if (ret_val == 0)
                ixgbe_set_pcie_completion_timeout(hw);
@@ -1241,14 +1241,14 @@ static void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw)
 }
 
 /**
- * ixgbe_set_rxpba_82598 - Configure packet buffers
+ * ixgbe_set_rxpba_82598 - Initialize RX packet buffer
  * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
- *
- * Configure packet buffers.
- */
-static void ixgbe_set_rxpba_82598(struct ixgbe_hw *hw, int num_pb, u32 headroom,
-                                 int strategy)
+ * @num_pb: number of packet buffers to allocate
+ * @headroom: reserve n KB of headroom
+ * @strategy: packet buffer allocation strategy
+ **/
+static void ixgbe_set_rxpba_82598(struct ixgbe_hw *hw, int num_pb,
+                                 u32 headroom, int strategy)
 {
        u32 rxpktsize = IXGBE_RXPBSIZE_64KB;
        u8  i = 0;
index b96cefd5a2eb48d6f0f4eeeccbc795e249a6c597..3bc9b67188751615169e40c5b627b11067933a99 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -270,6 +271,7 @@ static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw)
        mac->mcft_size = IXGBE_82599_MC_TBL_SIZE;
        mac->vft_size = IXGBE_82599_VFT_TBL_SIZE;
        mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES;
+       mac->rx_pb_size = IXGBE_82599_RX_PB_SIZE;
        mac->max_rx_queues = IXGBE_82599_MAX_RX_QUEUES;
        mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES;
        mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
@@ -510,7 +512,7 @@ out:
  *
  * Disables link, should be called during D3 power down sequence.
  *
- */
+ **/
 static void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw)
 {
        u32 autoc2_reg;
@@ -1003,8 +1005,7 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
 
 out:
        if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL))
-               hw_dbg(hw, "Smartspeed has downgraded the link speed from "
-                      "the maximum advertised\n");
+               hw_dbg(hw, "Smartspeed has downgraded the link speed from the maximum advertised\n");
        return status;
 }
 
@@ -1112,8 +1113,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
                                if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
                                        status =
                                                IXGBE_ERR_AUTONEG_NOT_COMPLETE;
-                                       hw_dbg(hw, "Autoneg did not "
-                                              "complete.\n");
+                                       hw_dbg(hw, "Autoneg did not complete.\n");
                                }
                        }
                }
@@ -2025,7 +2025,6 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw)
 
        /* We need to run link autotry after the driver loads */
        hw->mac.autotry_restart = true;
-       hw->mac.rx_pb_size = IXGBE_82599_RX_PB_SIZE;
 
        if (ret_val == 0)
                ret_val = ixgbe_verify_fw_version_82599(hw);
index 4456c235a44a8d579c0cf128d1f57ef9f900e42d..6149c6574106302c6c28d038025906458945f743 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index ef0fd4cef5df415d685a065de311ac2d5579c5a4..d1d67ba54775b2fa166ccec6fed4029cab066b9e 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 05e23b80b5e37b70f1f0e18a0b3be826915623c3..bdb99b3b0f30f4ee2253e81bc72e84fb6a0d1e30 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index d71d9ce3e394b4199f297ebbcb493fa268092dd2..d5a1e3db0774a5580b8191126e682c33191f7fa6 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index c5933f6dceee928be6c225cb6eba42c48284b011..472b0f450bf90d4dc23fe5995d28d0d80c2d940e 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index f2d35c04159cae88ab6f7218168c1c151533bce7..6c55c14d082aa6285f43941e5d96ae86acdbb21b 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -1127,10 +1128,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
                }
 
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->syncp);
                        data[i]   = ring->stats.packets;
                        data[i+1] = ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                i += 2;
 #ifdef BP_EXTENDED_STATS
                data[i] = ring->stats.yields;
@@ -1155,10 +1156,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
                }
 
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->syncp);
                        data[i]   = ring->stats.packets;
                        data[i+1] = ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                i += 2;
 #ifdef BP_EXTENDED_STATS
                data[i] = ring->stats.yields;
index f58db453a97edd8d6d6f7dfbccb2c6f8edd1f3d3..39557e3498a2c871063266aa5872abf203f2aa5b 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -585,7 +586,7 @@ static int ixgbe_fcoe_dma_pool_alloc(struct ixgbe_fcoe *fcoe,
        struct dma_pool *pool;
        char pool_name[32];
 
-       snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%d", cpu);
+       snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%u", cpu);
 
        pool = dma_pool_create(pool_name, dev, IXGBE_FCPTR_MAX,
                               IXGBE_FCPTR_ALIGN, PAGE_SIZE);
index 3a02759b5e95bccb7d7101a70067531ac5f43a93..b16cc786750dec8bb7bf29749db331a31f028ec9 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 0834e1ea44bcf4b94f667cbf62e5387fbfc61133..2067d392cc3d33850254e9a2d719a2db6491b6f5 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 10b35d82e3091a33b95aa28f6d4cb2eb259a430f..18cd8ca319ea03301fd9c507f222782b56f23cd4 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -1311,7 +1312,9 @@ static inline void ixgbe_rx_hash(struct ixgbe_ring *ring,
                                 struct sk_buff *skb)
 {
        if (ring->netdev->features & NETIF_F_RXHASH)
-               skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+               skb_set_hash(skb,
+                            le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+                            PKT_HASH_TYPE_L3);
 }
 
 #ifdef IXGBE_FCOE
@@ -2073,7 +2076,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 #endif /* IXGBE_FCOE */
        u16 cleaned_count = ixgbe_desc_unused(rx_ring);
 
-       do {
+       while (likely(total_rx_packets < budget)) {
                union ixgbe_adv_rx_desc *rx_desc;
                struct sk_buff *skb;
 
@@ -2148,7 +2151,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 
                /* update budget accounting */
                total_rx_packets++;
-       } while (likely(total_rx_packets < budget));
+       }
 
        u64_stats_update_begin(&rx_ring->syncp);
        rx_ring->stats.packets += total_rx_packets;
@@ -7290,10 +7293,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
 
                if (ring) {
                        do {
-                               start = u64_stats_fetch_begin_bh(&ring->syncp);
+                               start = u64_stats_fetch_begin_irq(&ring->syncp);
                                packets = ring->stats.packets;
                                bytes   = ring->stats.bytes;
-                       } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                        stats->rx_packets += packets;
                        stats->rx_bytes   += bytes;
                }
@@ -7306,10 +7309,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
 
                if (ring) {
                        do {
-                               start = u64_stats_fetch_begin_bh(&ring->syncp);
+                               start = u64_stats_fetch_begin_irq(&ring->syncp);
                                packets = ring->stats.packets;
                                bytes   = ring->stats.bytes;
-                       } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                        stats->tx_packets += packets;
                        stats->tx_bytes   += bytes;
                }
index cc3101afd29fe8745d0cd870271b3f5246ee88fa..f5c6af2b891bd3dc797e7c4f5640b006eac78810 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index e44ff47659b50b733cce7a17ce7a06ba010d7ce8..a9b9ad69ed0ec315d22d38c92eb1885c2900c9c3 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index d2caae4750e0cfcf9c783a5692d16c767c1261d7..ad51c12cb26a63fc3a8975e7527450e675f4133c 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index b4d4323666b8acce776fb1d34f9022c3729c860d..478eca9761ca9f6cdc49ca3d731eb4d85dbfd20f 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 9ef730f2916ade4ab887fe9be4e8f394d0f399f3..44ac9aef6a8d51d0371368525c4038e5faa0b2e1 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index dff0977876f75448ee67ef6e1305bdc8b5e8be22..e6c68d396c992fffb329a1cca4daadb47169faab 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 8bd29190514e4a7be7fd498cb28a0bef1336d082..139eaddfb2ed5c8c14a3891137a313b4fcaa3a6a 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index e74ae3682733df328b8b9f85631da133778bc9ee..ef6df3d6437e3102224adef7033a3b26f058ef7e 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index c10382e5aabc68a26f3ad9bbb8c94d49afc976f4..69271bc1b227ea77aa4c6e0043f6811edc62d974 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index c870f37f15d331320ae2d7d3ef90fb4d1083fc7c..2e0e5ec5d61f598c19a627fbd02abec4fcf92048 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -61,6 +62,7 @@ static s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw)
        mac->mcft_size = IXGBE_X540_MC_TBL_SIZE;
        mac->vft_size = IXGBE_X540_VFT_TBL_SIZE;
        mac->num_rar_entries = IXGBE_X540_RAR_ENTRIES;
+       mac->rx_pb_size = IXGBE_X540_RX_PB_SIZE;
        mac->max_rx_queues = IXGBE_X540_MAX_RX_QUEUES;
        mac->max_tx_queues = IXGBE_X540_MAX_TX_QUEUES;
        mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
@@ -187,7 +189,6 @@ static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw)
                goto out;
 
        ret_val = ixgbe_start_hw_gen2(hw);
-       hw->mac.rx_pb_size = IXGBE_X540_RX_PB_SIZE;
 out:
        return ret_val;
 }
index 57e0cd89b3dc6872f2a8991e9f39f5ba9e39f8a6..8581079791fe695e2c49a8db1cf7b0039df64287 100644 (file)
@@ -516,7 +516,8 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
                /* Workaround hardware that can't do proper VEPA multicast
                 * source pruning.
                 */
-               if ((skb->pkt_type & (PACKET_BROADCAST | PACKET_MULTICAST)) &&
+               if ((skb->pkt_type == PACKET_BROADCAST ||
+                   skb->pkt_type == PACKET_MULTICAST) &&
                    ether_addr_equal(rx_ring->netdev->dev_addr,
                                     eth_hdr(skb)->h_source)) {
                        dev_kfree_skb_irq(skb);
@@ -3279,7 +3280,6 @@ static int ixgbevf_resume(struct pci_dev *pdev)
        struct ixgbevf_adapter *adapter = netdev_priv(netdev);
        u32 err;
 
-       pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        /*
         * pci_restore_state clears dev->state_saved so call
@@ -3337,10 +3337,10 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
        for (i = 0; i < adapter->num_rx_queues; i++) {
                ring = adapter->rx_ring[i];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->syncp);
                        bytes = ring->stats.bytes;
                        packets = ring->stats.packets;
-               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                stats->rx_bytes += bytes;
                stats->rx_packets += packets;
        }
@@ -3348,10 +3348,10 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
        for (i = 0; i < adapter->num_tx_queues; i++) {
                ring = adapter->tx_ring[i];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->syncp);
                        bytes = ring->stats.bytes;
                        packets = ring->stats.packets;
-               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                stats->tx_bytes += bytes;
                stats->tx_packets += packets;
        }
index 12c6a66e54d12d1b995a88f4ba2c63a5d89feaf5..f3afcbdbb725c3d055a2ce10734cea17ab11ca64 100644 (file)
@@ -508,12 +508,12 @@ struct rtnl_link_stats64 *mvneta_get_stats64(struct net_device *dev,
 
                cpu_stats = per_cpu_ptr(pp->stats, cpu);
                do {
-                       start = u64_stats_fetch_begin_bh(&cpu_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
                        rx_packets = cpu_stats->rx_packets;
                        rx_bytes   = cpu_stats->rx_bytes;
                        tx_packets = cpu_stats->tx_packets;
                        tx_bytes   = cpu_stats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
 
                stats->rx_packets += rx_packets;
                stats->rx_bytes   += rx_bytes;
index 55a37ae11440791d78e5dd69bf486cb5b4f976f3..d524676fdff4697627930dd03e9c2d1a822efd75 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/prefetch.h>
 #include <linux/debugfs.h>
 #include <linux/mii.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
 
 #include <asm/irq.h>
 
@@ -2733,6 +2735,9 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
        unsigned int total_bytes[2] = { 0 };
        unsigned int total_packets[2] = { 0 };
 
+       if (to_do <= 0)
+               return work_done;
+
        rmb();
        do {
                struct sky2_port *sky2;
@@ -3906,19 +3911,19 @@ static struct rtnl_link_stats64 *sky2_get_stats(struct net_device *dev,
        u64 _bytes, _packets;
 
        do {
-               start = u64_stats_fetch_begin_bh(&sky2->rx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&sky2->rx_stats.syncp);
                _bytes = sky2->rx_stats.bytes;
                _packets = sky2->rx_stats.packets;
-       } while (u64_stats_fetch_retry_bh(&sky2->rx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&sky2->rx_stats.syncp, start));
 
        stats->rx_packets = _packets;
        stats->rx_bytes = _bytes;
 
        do {
-               start = u64_stats_fetch_begin_bh(&sky2->tx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&sky2->tx_stats.syncp);
                _bytes = sky2->tx_stats.bytes;
                _packets = sky2->tx_stats.packets;
-       } while (u64_stats_fetch_retry_bh(&sky2->tx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&sky2->tx_stats.syncp, start));
 
        stats->tx_packets = _packets;
        stats->tx_bytes = _bytes;
@@ -4748,6 +4753,7 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
 {
        struct sky2_port *sky2;
        struct net_device *dev = alloc_etherdev(sizeof(*sky2));
+       const void *iap;
 
        if (!dev)
                return NULL;
@@ -4805,8 +4811,16 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
 
        dev->features |= dev->hw_features;
 
-       /* read the mac address */
-       memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
+       /* try to get mac address in the following order:
+        * 1) from device tree data
+        * 2) from internal registers set by bootloader
+        */
+       iap = of_get_mac_address(hw->pdev->dev.of_node);
+       if (iap)
+               memcpy(dev->dev_addr, iap, ETH_ALEN);
+       else
+               memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8,
+                             ETH_ALEN);
 
        return dev;
 }
index 0d02fba9453657588b5f3db7b2e90e7e5410b010..2b0b45ece14b203ce0ba08f0bafc90e65ba38274 100644 (file)
@@ -2289,6 +2289,30 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
 }
 EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
 
+ /* mlx4_get_slave_default_vlan -
+ * return true if VST ( default vlan)
+ * if VST, will return vlan & qos (if not NULL)
+ */
+bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave,
+                                u16 *vlan, u8 *qos)
+{
+       struct mlx4_vport_oper_state *vp_oper;
+       struct mlx4_priv *priv;
+
+       priv = mlx4_priv(dev);
+       vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+
+       if (MLX4_VGT != vp_oper->state.default_vlan) {
+               if (vlan)
+                       *vlan = vp_oper->state.default_vlan;
+               if (qos)
+                       *qos = vp_oper->state.default_qos;
+               return true;
+       }
+       return false;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan);
+
 int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
index 3454437fcd95121e9a12f1bcde87dc9de96cd4c6..0c59d4fe7e3aae56afee09b7e279601192c9e26e 100644 (file)
@@ -332,7 +332,7 @@ static struct mlx4_interface mlx4_en_interface = {
        .protocol       = MLX4_PROT_ETH,
 };
 
-void mlx4_en_verify_params(void)
+static void mlx4_en_verify_params(void)
 {
        if (pfctx > MAX_PFC_TX) {
                pr_warn("mlx4_en: WARNING: illegal module parameter pfctx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n",
index 3db594614fd39176ac0137a8fe34f31eb950e7a1..fa5ee719e04bddbb60ad71e4a966727b69ff0cc7 100644 (file)
@@ -742,6 +742,14 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
                                err = mlx4_en_uc_steer_add(priv, new_mac,
                                                           &qpn,
                                                           &entry->reg_id);
+                               if (err)
+                                       return err;
+                               if (priv->tunnel_reg_id) {
+                                       mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id);
+                                       priv->tunnel_reg_id = 0;
+                               }
+                               err = mlx4_en_tunnel_steer_add(priv, new_mac, qpn,
+                                                              &priv->tunnel_reg_id);
                                return err;
                        }
                }
@@ -1780,6 +1788,8 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
                mc_list[5] = priv->port;
                mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
                                      mc_list, MLX4_PROT_ETH, mclist->reg_id);
+               if (mclist->tunnel_reg_id)
+                       mlx4_flow_detach(mdev->dev, mclist->tunnel_reg_id);
        }
        mlx4_en_clear_list(dev);
        list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) {
index 8afb72ec957d81222d226302a47ea1681d4bfcf6..ba049ae88749dac986a0712d281bbd649152acdd 100644 (file)
@@ -661,6 +661,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
        if (!priv->port_up)
                return 0;
 
+       if (budget <= 0)
+               return polled;
+
        /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx
         * descriptor offset can be deduced from the CQE index instead of
         * reading 'cqe->index' */
index 69c2fcef9d4cb79209a97b27f81e3fad27a776fd..dd1f6d346459808dfe95690ce5fcf0af31e99231 100644 (file)
@@ -314,7 +314,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                        }
                }
        }
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return tx_info->nr_txbb;
 }
 
index 9cdf452140daab876713f12245e84de3978875de..d0d8dd8325578a7c89fc2f045ff7c785e2086392 100644 (file)
@@ -129,13 +129,14 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
                [0] = "RSS support",
                [1] = "RSS Toeplitz Hash Function support",
                [2] = "RSS XOR Hash Function support",
-               [3] = "Device manage flow steering support",
+               [3] = "Device managed flow steering support",
                [4] = "Automatic MAC reassignment support",
                [5] = "Time stamping support",
                [6] = "VST (control vlan insertion/stripping) support",
                [7] = "FSM (MAC anti-spoofing) support",
                [8] = "Dynamic QP updates support",
-               [9] = "TCP/IP offloads/flow-steering for VXLAN support"
+               [9] = "Device managed flow steering IPoIB support",
+               [10] = "TCP/IP offloads/flow-steering for VXLAN support"
        };
        int i;
 
@@ -859,7 +860,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
 
        /* For guests, disable vxlan tunneling */
-       MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN);
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VXLAN);
        field &= 0xf7;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN);
 
@@ -869,7 +870,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET);
 
        /* For guests, disable mw type 2 */
-       MLX4_GET(bmme_flags, outbox, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+       MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
        bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN;
        MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
 
@@ -883,7 +884,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        }
 
        /* turn off ipoib managed steering for guests */
-       MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
        field &= ~0x80;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
 
@@ -934,7 +935,10 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
                MLX4_PUT(outbox->buf, port_type,
                         QUERY_PORT_SUPPORTED_TYPE_OFFSET);
 
-               short_field = 1; /* slave max gids */
+               if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH)
+                       short_field = mlx4_get_slave_num_gids(dev, slave);
+               else
+                       short_field = 1; /* slave max gids */
                MLX4_PUT(outbox->buf, short_field,
                         QUERY_PORT_CUR_MAX_GID_OFFSET);
 
index 979ea4364efbc86baaddc83eaa6b0a99f8a55278..abd0b1d277aaee2778a7103b799999e3b0cf5c41 100644 (file)
@@ -149,6 +149,8 @@ struct mlx4_port_config {
        struct pci_dev *pdev;
 };
 
+static atomic_t pf_loading = ATOMIC_INIT(0);
+
 int mlx4_check_port_params(struct mlx4_dev *dev,
                           enum mlx4_port_type *port_type)
 {
@@ -748,7 +750,7 @@ static void mlx4_request_modules(struct mlx4_dev *dev)
                        has_eth_port = true;
        }
 
-       if (has_ib_port)
+       if (has_ib_port || (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
                request_module_nowait(IB_DRV_NAME);
        if (has_eth_port)
                request_module_nowait(EN_DRV_NAME);
@@ -1406,6 +1408,11 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
        u32 slave_read;
        u32 cmd_channel_ver;
 
+       if (atomic_read(&pf_loading)) {
+               mlx4_warn(dev, "PF is not ready. Deferring probe\n");
+               return -EPROBE_DEFER;
+       }
+
        mutex_lock(&priv->cmd.slave_cmd_mutex);
        priv->cmd.max_cmds = 1;
        mlx4_warn(dev, "Sending reset\n");
@@ -1462,7 +1469,11 @@ static void mlx4_parav_master_pf_caps(struct mlx4_dev *dev)
        int i;
 
        for (i = 1; i <= dev->caps.num_ports; i++) {
-               dev->caps.gid_table_len[i] = 1;
+               if (dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH)
+                       dev->caps.gid_table_len[i] =
+                               mlx4_get_slave_num_gids(dev, 0);
+               else
+                       dev->caps.gid_table_len[i] = 1;
                dev->caps.pkey_table_len[i] =
                        dev->phys_caps.pkey_phys_table_len[i] - 1;
        }
@@ -2307,7 +2318,11 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
 
                if (num_vfs) {
                        mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", num_vfs);
+
+                       atomic_inc(&pf_loading);
                        err = pci_enable_sriov(pdev, num_vfs);
+                       atomic_dec(&pf_loading);
+
                        if (err) {
                                mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n",
                                         err);
@@ -2672,6 +2687,7 @@ static struct pci_driver mlx4_driver = {
        .name           = DRV_NAME,
        .id_table       = mlx4_pci_table,
        .probe          = mlx4_init_one,
+       .shutdown       = mlx4_remove_one,
        .remove         = mlx4_remove_one,
        .err_handler    = &mlx4_err_handler,
 };
index 6b65f77952153f5dd1ceab2d074e456b2a9567c4..6ba38c98c49245e447fc9fa919779c7c3ccf669a 100644 (file)
@@ -51,8 +51,8 @@
 
 #define DRV_NAME       "mlx4_core"
 #define PFX            DRV_NAME ": "
-#define DRV_VERSION    "1.1"
-#define DRV_RELDATE    "Dec, 2011"
+#define DRV_VERSION    "2.2-1"
+#define DRV_RELDATE    "Feb, 2014"
 
 #define MLX4_FS_UDP_UC_EN              (1 << 1)
 #define MLX4_FS_TCP_UC_EN              (1 << 2)
@@ -788,6 +788,10 @@ enum {
        MLX4_USE_RR     = 1,
 };
 
+struct mlx4_roce_gid_entry {
+       u8 raw[16];
+};
+
 struct mlx4_priv {
        struct mlx4_dev         dev;
 
@@ -834,6 +838,7 @@ struct mlx4_priv {
        int                     fs_hash_mode;
        u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
        __be64                  slave_node_guids[MLX4_MFUNC_MAX];
+       struct mlx4_roce_gid_entry roce_gids[MLX4_MAX_PORTS][MLX4_ROCE_MAX_GIDS];
 
        atomic_t                opreq_count;
        struct work_struct      opreq_task;
@@ -1282,4 +1287,7 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work);
 
 void mlx4_init_quotas(struct mlx4_dev *dev);
 
+int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave);
+int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave);
+
 #endif /* MLX4_H */
index 4ff7da83c4b3587139be927a6074e1fadfdb8a3b..69e1f36858e0cb9336b650aed6406a66d65a170c 100644 (file)
@@ -57,8 +57,8 @@
 #include "en_port.h"
 
 #define DRV_NAME       "mlx4_en"
-#define DRV_VERSION    "2.0"
-#define DRV_RELDATE    "Dec 2011"
+#define DRV_VERSION    "2.2-1"
+#define DRV_RELDATE    "Feb 2014"
 
 #define MLX4_EN_MSG_LEVEL      (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
 
index a58bcbf1b8067e88e5e153f25cd285ef57b90bb3..ece328166e94d7237c6af8f90b0ee1d579927954 100644 (file)
@@ -505,6 +505,32 @@ int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
        mlx4_free_cmd_mailbox(dev, outmailbox);
        return err;
 }
+static struct mlx4_roce_gid_entry zgid_entry;
+
+int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave)
+{
+       if (slave == 0)
+               return MLX4_ROCE_PF_GIDS;
+       if (slave <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % dev->num_vfs))
+               return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs) + 1;
+       return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs;
+}
+
+int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave)
+{
+       int gids;
+       int vfs;
+
+       gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
+       vfs = dev->num_vfs;
+
+       if (slave == 0)
+               return 0;
+       if (slave <= gids % vfs)
+               return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1);
+
+       return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1));
+}
 
 static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
                                u8 op_mod, struct mlx4_cmd_mailbox *inbox)
@@ -515,14 +541,18 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
        struct mlx4_slave_state *slave_st = &master->slave_state[slave];
        struct mlx4_set_port_rqp_calc_context *qpn_context;
        struct mlx4_set_port_general_context *gen_context;
+       struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
        int reset_qkey_viols;
        int port;
        int is_eth;
+       int num_gids;
+       int base;
        u32 in_modifier;
        u32 promisc;
        u16 mtu, prev_mtu;
        int err;
-       int i;
+       int i, j;
+       int offset;
        __be32 agg_cap_mask;
        __be32 slave_cap_mask;
        __be32 new_cap_mask;
@@ -535,7 +565,8 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
        /* Slaves cannot perform SET_PORT operations except changing MTU */
        if (is_eth) {
                if (slave != dev->caps.function &&
-                   in_modifier != MLX4_SET_PORT_GENERAL) {
+                   in_modifier != MLX4_SET_PORT_GENERAL &&
+                   in_modifier != MLX4_SET_PORT_GID_TABLE) {
                        mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
                                        slave);
                        return -EINVAL;
@@ -581,6 +612,67 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
 
                        gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
                        break;
+               case MLX4_SET_PORT_GID_TABLE:
+                       /* change to MULTIPLE entries: number of guest's gids
+                        * need a FOR-loop here over number of gids the guest has.
+                        * 1. Check no duplicates in gids passed by slave
+                        */
+                       num_gids = mlx4_get_slave_num_gids(dev, slave);
+                       base = mlx4_get_base_gid_ix(dev, slave);
+                       gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+                       for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
+                               if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
+                                           sizeof(zgid_entry)))
+                                       continue;
+                               gid_entry_mb1 = gid_entry_mbox + 1;
+                               for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
+                                       if (!memcmp(gid_entry_mb1->raw,
+                                                   zgid_entry.raw, sizeof(zgid_entry)))
+                                               continue;
+                                       if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
+                                                   sizeof(gid_entry_mbox->raw))) {
+                                               /* found duplicate */
+                                               return -EINVAL;
+                                       }
+                               }
+                       }
+
+                       /* 2. Check that do not have duplicates in OTHER
+                        *    entries in the port GID table
+                        */
+                       for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
+                               if (i >= base && i < base + num_gids)
+                                       continue; /* don't compare to slave's current gids */
+                               gid_entry_tbl = &priv->roce_gids[port - 1][i];
+                               if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
+                                       continue;
+                               gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+                               for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
+                                       if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
+                                                   sizeof(zgid_entry)))
+                                               continue;
+                                       if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
+                                                   sizeof(gid_entry_tbl->raw))) {
+                                               /* found duplicate */
+                                               mlx4_warn(dev, "requested gid entry for slave:%d "
+                                                         "is a duplicate of gid at index %d\n",
+                                                         slave, i);
+                                               return -EINVAL;
+                                       }
+                               }
+                       }
+
+                       /* insert slave GIDs with memcpy, starting at slave's base index */
+                       gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+                       for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
+                               memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16);
+
+                       /* Now, copy roce port gids table to current mailbox for passing to FW */
+                       gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+                       for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
+                               memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16);
+
+                       break;
                }
                return mlx4_cmd(dev, inbox->dma, in_mod, op_mod,
                                MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
@@ -927,3 +1019,51 @@ void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap)
                *stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK;
 }
 EXPORT_SYMBOL(mlx4_set_stats_bitmap);
+
+int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
+                                int *slave_id)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int i, found_ix = -1;
+       int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
+
+       if (!mlx4_is_mfunc(dev))
+               return -EINVAL;
+
+       for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
+               if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) {
+                       found_ix = i;
+                       break;
+               }
+       }
+
+       if (found_ix >= 0) {
+               if (found_ix < MLX4_ROCE_PF_GIDS)
+                       *slave_id = 0;
+               else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % dev->num_vfs) *
+                        (vf_gids / dev->num_vfs + 1))
+                       *slave_id = ((found_ix - MLX4_ROCE_PF_GIDS) /
+                                    (vf_gids / dev->num_vfs + 1)) + 1;
+               else
+                       *slave_id =
+                       ((found_ix - MLX4_ROCE_PF_GIDS -
+                         ((vf_gids % dev->num_vfs) * ((vf_gids / dev->num_vfs + 1)))) /
+                        (vf_gids / dev->num_vfs)) + vf_gids % dev->num_vfs + 1;
+       }
+
+       return (found_ix >= 0) ? 0 : -EINVAL;
+}
+EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
+
+int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
+                                u8 *gid)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       if (!mlx4_is_master(dev))
+               return -EINVAL;
+
+       memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16);
+       return 0;
+}
+EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
index 57428a0cb9ddc37fd226cb22305323185eda22fd..74e490d70184e9a312ba3961368f535102be4fc5 100644 (file)
@@ -52,6 +52,8 @@
 struct mac_res {
        struct list_head list;
        u64 mac;
+       int ref_count;
+       u8 smac_index;
        u8 port;
 };
 
@@ -219,6 +221,11 @@ struct res_fs_rule {
        int                     qpn;
 };
 
+static int mlx4_is_eth(struct mlx4_dev *dev, int port)
+{
+       return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1;
+}
+
 static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
 {
        struct rb_node *node = root->rb_node;
@@ -600,15 +607,34 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
        struct mlx4_qp_context  *qp_ctx = inbox->buf + 8;
        enum mlx4_qp_optpar     optpar = be32_to_cpu(*(__be32 *) inbox->buf);
        u32                     ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
+       int port;
 
-       if (MLX4_QP_ST_UD == ts)
-               qp_ctx->pri_path.mgid_index = 0x80 | slave;
-
-       if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_UC == ts) {
-               if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH)
-                       qp_ctx->pri_path.mgid_index = slave & 0x7F;
-               if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH)
-                       qp_ctx->alt_path.mgid_index = slave & 0x7F;
+       if (MLX4_QP_ST_UD == ts) {
+               port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+               if (mlx4_is_eth(dev, port))
+                       qp_ctx->pri_path.mgid_index = mlx4_get_base_gid_ix(dev, slave) | 0x80;
+               else
+                       qp_ctx->pri_path.mgid_index = slave | 0x80;
+
+       } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) {
+               if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
+                       port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+                       if (mlx4_is_eth(dev, port)) {
+                               qp_ctx->pri_path.mgid_index += mlx4_get_base_gid_ix(dev, slave);
+                               qp_ctx->pri_path.mgid_index &= 0x7f;
+                       } else {
+                               qp_ctx->pri_path.mgid_index = slave & 0x7F;
+                       }
+               }
+               if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
+                       port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
+                       if (mlx4_is_eth(dev, port)) {
+                               qp_ctx->alt_path.mgid_index += mlx4_get_base_gid_ix(dev, slave);
+                               qp_ctx->alt_path.mgid_index &= 0x7f;
+                       } else {
+                               qp_ctx->alt_path.mgid_index = slave & 0x7F;
+                       }
+               }
        }
 }
 
@@ -619,7 +645,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
        struct mlx4_qp_context  *qpc = inbox->buf + 8;
        struct mlx4_vport_oper_state *vp_oper;
        struct mlx4_priv *priv;
-       u32 qp_type;
        int port;
 
        port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
@@ -627,12 +652,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
        vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
 
        if (MLX4_VGT != vp_oper->state.default_vlan) {
-               qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
-               if (MLX4_QP_ST_RC == qp_type ||
-                   (MLX4_QP_ST_UD == qp_type &&
-                    !mlx4_is_qp_reserved(dev, qpn)))
-                       return -EINVAL;
-
                /* the reserved QPs (special, proxy, tunnel)
                 * do not operate over vlans
                 */
@@ -1659,11 +1678,39 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        return err;
 }
 
-static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port)
+static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port,
+                                    u8 smac_index, u64 *mac)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
-       struct mac_res *res;
+       struct list_head *mac_list =
+               &tracker->slave_list[slave].res_list[RES_MAC];
+       struct mac_res *res, *tmp;
+
+       list_for_each_entry_safe(res, tmp, mac_list, list) {
+               if (res->smac_index == smac_index && res->port == (u8) port) {
+                       *mac = res->mac;
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
+       struct list_head *mac_list =
+               &tracker->slave_list[slave].res_list[RES_MAC];
+       struct mac_res *res, *tmp;
+
+       list_for_each_entry_safe(res, tmp, mac_list, list) {
+               if (res->mac == mac && res->port == (u8) port) {
+                       /* mac found. update ref count */
+                       ++res->ref_count;
+                       return 0;
+               }
+       }
 
        if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))
                return -EINVAL;
@@ -1674,6 +1721,8 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port)
        }
        res->mac = mac;
        res->port = (u8) port;
+       res->smac_index = smac_index;
+       res->ref_count = 1;
        list_add_tail(&res->list,
                      &tracker->slave_list[slave].res_list[RES_MAC]);
        return 0;
@@ -1690,9 +1739,11 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,
 
        list_for_each_entry_safe(res, tmp, mac_list, list) {
                if (res->mac == mac && res->port == (u8) port) {
-                       list_del(&res->list);
-                       mlx4_release_resource(dev, slave, RES_MAC, 1, port);
-                       kfree(res);
+                       if (!--res->ref_count) {
+                               list_del(&res->list);
+                               mlx4_release_resource(dev, slave, RES_MAC, 1, port);
+                               kfree(res);
+                       }
                        break;
                }
        }
@@ -1705,10 +1756,13 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave)
        struct list_head *mac_list =
                &tracker->slave_list[slave].res_list[RES_MAC];
        struct mac_res *res, *tmp;
+       int i;
 
        list_for_each_entry_safe(res, tmp, mac_list, list) {
                list_del(&res->list);
-               __mlx4_unregister_mac(dev, res->port, res->mac);
+               /* dereference the mac the num times the slave referenced it */
+               for (i = 0; i < res->ref_count; i++)
+                       __mlx4_unregister_mac(dev, res->port, res->mac);
                mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);
                kfree(res);
        }
@@ -1720,6 +1774,7 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        int err = -EINVAL;
        int port;
        u64 mac;
+       u8 smac_index;
 
        if (op != RES_OP_RESERVE_AND_MAP)
                return err;
@@ -1729,12 +1784,13 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
 
        err = __mlx4_register_mac(dev, port, mac);
        if (err >= 0) {
+               smac_index = err;
                set_param_l(out_param, err);
                err = 0;
        }
 
        if (!err) {
-               err = mac_add_to_slave(dev, slave, mac, port);
+               err = mac_add_to_slave(dev, slave, mac, port, smac_index);
                if (err)
                        __mlx4_unregister_mac(dev, port, mac);
        }
@@ -2734,6 +2790,8 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
        u32                     qp_type;
        struct mlx4_qp_context  *qp_ctx;
        enum mlx4_qp_optpar     optpar;
+       int port;
+       int num_gids;
 
        qp_ctx  = inbox->buf + 8;
        qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
@@ -2741,6 +2799,7 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
 
        switch (qp_type) {
        case MLX4_QP_ST_RC:
+       case MLX4_QP_ST_XRC:
        case MLX4_QP_ST_UC:
                switch (transition) {
                case QP_TRANS_INIT2RTR:
@@ -2749,13 +2808,24 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
                case QP_TRANS_SQD2SQD:
                case QP_TRANS_SQD2RTS:
                        if (slave != mlx4_master_func_num(dev))
-                               /* slaves have only gid index 0 */
-                               if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH)
-                                       if (qp_ctx->pri_path.mgid_index)
+                               if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
+                                       port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+                                       if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
+                                               num_gids = mlx4_get_slave_num_gids(dev, slave);
+                                       else
+                                               num_gids = 1;
+                                       if (qp_ctx->pri_path.mgid_index >= num_gids)
                                                return -EINVAL;
-                               if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH)
-                                       if (qp_ctx->alt_path.mgid_index)
+                               }
+                               if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
+                                       port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
+                                       if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
+                                               num_gids = mlx4_get_slave_num_gids(dev, slave);
+                                       else
+                                               num_gids = 1;
+                                       if (qp_ctx->alt_path.mgid_index >= num_gids)
                                                return -EINVAL;
+                               }
                        break;
                default:
                        break;
@@ -3268,6 +3338,25 @@ int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
        return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
 }
 
+static int roce_verify_mac(struct mlx4_dev *dev, int slave,
+                               struct mlx4_qp_context *qpc,
+                               struct mlx4_cmd_mailbox *inbox)
+{
+       u64 mac;
+       int port;
+       u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
+       u8 sched = *(u8 *)(inbox->buf + 64);
+       u8 smac_ix;
+
+       port = (sched >> 6 & 1) + 1;
+       if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) {
+               smac_ix = qpc->pri_path.grh_mylmc & 0x7f;
+               if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac))
+                       return -ENOENT;
+       }
+       return 0;
+}
+
 int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
                             struct mlx4_vhcr *vhcr,
                             struct mlx4_cmd_mailbox *inbox,
@@ -3290,6 +3379,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
        if (err)
                return err;
 
+       if (roce_verify_mac(dev, slave, qpc, inbox))
+               return -EINVAL;
+
        update_pkey_index(dev, slave, inbox);
        update_gid(dev, inbox, (u8)slave);
        adjust_proxy_tun_qkey(dev, vhcr, qpc);
index 81df046a6d69cd7bb4e1745b9553aa1de3b89e23..77ac95f052da81e31608891129141e43f9e61659 100644 (file)
@@ -46,8 +46,8 @@
 #include "mlx5_core.h"
 
 #define DRIVER_NAME "mlx5_core"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
 
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library");
@@ -531,7 +531,6 @@ static int __init init(void)
 
        return 0;
 
-       mlx5_health_cleanup();
 err_debug:
        mlx5_unregister_debugfs();
        return err;
index 56e3a9d42bb2f2bae40fdda6afe0d9cf1717b95b..d44fdb91808e0c5ef53970a608751ddd5363501b 100644 (file)
@@ -2914,6 +2914,9 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget)
        struct RxD1 *rxdp1;
        struct RxD3 *rxdp3;
 
+       if (budget <= 0)
+               return napi_pkts;
+
        get_info = ring_data->rx_curr_get_info;
        get_block = get_info.block_index;
        memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
index c83cedd26dec637eaec9b4c505730adef028658c..11adc89959c18838b78bf9602a962018c312751a 100644 (file)
@@ -368,6 +368,9 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
        vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
                ring->ndev->name, __func__, __LINE__);
 
+       if (ring->budget <= 0)
+               goto out;
+
        do {
                prefetch((char *)dtr + L1_CACHE_BYTES);
                rx_priv = vxge_hw_ring_rxd_private_get(dtr);
@@ -525,6 +528,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
        if (first_dtr)
                vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr);
 
+out:
        vxge_debug_entryexit(VXGE_TRACE,
                                "%s:%d  Exiting...",
                                __func__, __LINE__);
@@ -3134,12 +3138,12 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
                u64 packets, bytes, multicast;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&rxstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&rxstats->syncp);
 
                        packets   = rxstats->rx_frms;
                        multicast = rxstats->rx_mcast;
                        bytes     = rxstats->rx_bytes;
-               } while (u64_stats_fetch_retry_bh(&rxstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start));
 
                net_stats->rx_packets += packets;
                net_stats->rx_bytes += bytes;
@@ -3149,11 +3153,11 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
                net_stats->rx_dropped += rxstats->rx_dropped;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&txstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&txstats->syncp);
 
                        packets = txstats->tx_frms;
                        bytes   = txstats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&txstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&txstats->syncp, start));
 
                net_stats->tx_packets += packets;
                net_stats->tx_bytes += bytes;
index bad3c057ee8a98a7463e0e52582618f131098257..811be0bccd14969c3382d0f9320275ec5833df1a 100644 (file)
@@ -1753,19 +1753,19 @@ nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage)
 
        /* software stats */
        do {
-               syncp_start = u64_stats_fetch_begin_bh(&np->swstats_rx_syncp);
+               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp);
                storage->rx_packets       = np->stat_rx_packets;
                storage->rx_bytes         = np->stat_rx_bytes;
                storage->rx_dropped       = np->stat_rx_dropped;
                storage->rx_missed_errors = np->stat_rx_missed_errors;
-       } while (u64_stats_fetch_retry_bh(&np->swstats_rx_syncp, syncp_start));
+       } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start));
 
        do {
-               syncp_start = u64_stats_fetch_begin_bh(&np->swstats_tx_syncp);
+               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp);
                storage->tx_packets = np->stat_tx_packets;
                storage->tx_bytes   = np->stat_tx_bytes;
                storage->tx_dropped = np->stat_tx_dropped;
-       } while (u64_stats_fetch_retry_bh(&np->swstats_tx_syncp, syncp_start));
+       } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start));
 
        /* If the nic supports hw counters then retrieve latest values */
        if (np->driver_data & DEV_HAS_STATISTICS_V123) {
index 0f39778e0e5b1a530f9d2ed0596c9ce11d9c6940..3b83fbde4975dfeb94e7f0e75b14b1b5cb388b69 100644 (file)
@@ -345,6 +345,7 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter)
                        if (qlcnic_sriov_vf_check(adapter))
                                return -EINVAL;
                        num_msix = 1;
+                       adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
                        adapter->drv_tx_rings = QLCNIC_SINGLE_RING;
                }
        }
index 77f1bce432d2998b3d14b5b6f56c694a877a1ae6..7d4f54912bad526077b145109dc003e532b88d70 100644 (file)
@@ -807,7 +807,7 @@ qlcnic_dcb_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, u8 *prio,
            !type->tc_param_valid)
                return;
 
-       if (tc < 0 || (tc > QLC_DCB_MAX_TC))
+       if (tc < 0 || (tc >= QLC_DCB_MAX_TC))
                return;
 
        tc_cfg = &type->tc_cfg[tc];
@@ -843,7 +843,7 @@ static void qlcnic_dcb_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,
            !type->tc_param_valid)
                return;
 
-       if (pgid < 0 || pgid > QLC_DCB_MAX_PG)
+       if (pgid < 0 || pgid >= QLC_DCB_MAX_PG)
                return;
 
        pgcfg = &type->pg_cfg[pgid];
index a33547292878aed1dc7250c666969ac7f6f14151..4b92d9d90267ea4cac2f3c9eefa60316ad81f082 100644 (file)
@@ -825,9 +825,10 @@ static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter)
 
                if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
                        qlcnic_disable_multi_tx(adapter);
+                       adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
 
                        err = qlcnic_enable_msi_legacy(adapter);
-                       if (!err)
+                       if (err)
                                return err;
                }
        }
@@ -3872,7 +3873,7 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt,
                strcpy(buf, "Tx");
        }
 
-       if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
+       if (!QLCNIC_IS_MSI_FAMILY(adapter)) {
                netdev_err(netdev, "No RSS/TSS support in INT-x mode\n");
                return -EINVAL;
        }
index a28460cf873d3414b1a645f925325ab99d7cfffe..14f748cbf0deeb8cd4c6ccfa3039d08764ee1142 100644 (file)
@@ -13,8 +13,6 @@
 #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
 #define QLC_SRIOV_ALLOW_VLAN0  BIT_19
@@ -1210,13 +1208,6 @@ 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 737c1a881f781917061d8b39ad43762f62ee7a6e..2bc728e65e245424e34f69797d841f5b60af4d5c 100644 (file)
@@ -476,7 +476,7 @@ rx_status_loop:
        rx = 0;
        cpw16(IntrStatus, cp_rx_intr_mask);
 
-       while (1) {
+       while (rx < budget) {
                u32 status, len;
                dma_addr_t mapping, new_mapping;
                struct sk_buff *skb, *new_skb;
@@ -554,9 +554,6 @@ rx_next:
                else
                        desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
                rx_tail = NEXT_RX(rx_tail);
-
-               if (rx >= budget)
-                       break;
        }
 
        cp->rx_tail = rx_tail;
@@ -899,7 +896,7 @@ out_unlock:
 
        return NETDEV_TX_OK;
 out_dma_error:
-       kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        cp->dev->stats.tx_dropped++;
        goto out_unlock;
 }
index da5972eefdd2bfc5d702fd553cf68b91c5485fb5..2e5df148af4c7d6fa36c33f7543ef5c758db9368 100644 (file)
@@ -1717,9 +1717,9 @@ static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb,
                if (len < ETH_ZLEN)
                        memset(tp->tx_buf[entry], 0, ETH_ZLEN);
                skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
        } else {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                dev->stats.tx_dropped++;
                return NETDEV_TX_OK;
        }
@@ -2522,16 +2522,16 @@ rtl8139_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
        netdev_stats_to_stats64(stats, &dev->stats);
 
        do {
-               start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp);
                stats->rx_packets = tp->rx_stats.packets;
                stats->rx_bytes = tp->rx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start));
 
        do {
-               start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp);
                stats->tx_packets = tp->tx_stats.packets;
                stats->tx_bytes = tp->tx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start));
 
        return stats;
 }
index 91a67ae8f17b9bffc5bf86405a5788055b583ba0..aa1c079f231dc6f2cfc017cd4950f9ebb8e1e9da 100644 (file)
@@ -209,7 +209,7 @@ static const struct {
        [RTL_GIGA_MAC_VER_16] =
                _R("RTL8101e",          RTL_TD_0, NULL, JUMBO_1K, true),
        [RTL_GIGA_MAC_VER_17] =
-               _R("RTL8168b/8111b",    RTL_TD_1, NULL, JUMBO_4K, false),
+               _R("RTL8168b/8111b",    RTL_TD_0, NULL, JUMBO_4K, false),
        [RTL_GIGA_MAC_VER_18] =
                _R("RTL8168cp/8111cp",  RTL_TD_1, NULL, JUMBO_6K, false),
        [RTL_GIGA_MAC_VER_19] =
@@ -5834,7 +5834,7 @@ static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
                                             tp->TxDescArray + entry);
                        if (skb) {
                                tp->dev->stats.tx_dropped++;
-                               dev_kfree_skb(skb);
+                               dev_kfree_skb_any(skb);
                                tx_skb->skb = NULL;
                        }
                }
@@ -6059,7 +6059,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
 err_dma_1:
        rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
 err_dma_0:
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 err_update_stats:
        dev->stats.tx_dropped++;
        return NETDEV_TX_OK;
@@ -6142,7 +6142,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
                        tp->tx_stats.packets++;
                        tp->tx_stats.bytes += tx_skb->skb->len;
                        u64_stats_update_end(&tp->tx_stats.syncp);
-                       dev_kfree_skb(tx_skb->skb);
+                       dev_kfree_skb_any(tx_skb->skb);
                        tx_skb->skb = NULL;
                }
                dirty_tx++;
@@ -6590,17 +6590,17 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
                rtl8169_rx_missed(dev, ioaddr);
 
        do {
-               start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp);
                stats->rx_packets = tp->rx_stats.packets;
                stats->rx_bytes = tp->rx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start));
 
 
        do {
-               start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp);
                stats->tx_packets = tp->tx_stats.packets;
                stats->tx_bytes = tp->tx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start));
 
        stats->rx_dropped       = dev->stats.rx_dropped;
        stats->tx_dropped       = dev->stats.tx_dropped;
@@ -7118,6 +7118,8 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        mutex_init(&tp->wk.mutex);
+       u64_stats_init(&tp->rx_stats.syncp);
+       u64_stats_init(&tp->tx_stats.syncp);
 
        /* Get MAC address */
        for (i = 0; i < ETH_ALEN; i++)
index b1e6554f44bc552196c4eff0c2dc4ad5b914b814..efaca6d5e85b35b3e3144a1105b12051eca8d8c4 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2006-2012 Nobuhiro Iwamatsu
  *  Copyright (C) 2008-2014 Renesas Solutions Corp.
  *  Copyright (C) 2013-2014 Cogent Embedded, Inc.
+ *  Copyright (C) 2014 Codethink Limited
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms and conditions of the GNU General Public License,
@@ -40,6 +41,7 @@
 #include <linux/if_vlan.h>
 #include <linux/clk.h>
 #include <linux/sh_eth.h>
+#include <linux/of_mdio.h>
 
 #include "sh_eth.h"
 
@@ -398,7 +400,8 @@ static void sh_eth_select_mii(struct net_device *ndev)
                value = 0x0;
                break;
        default:
-               pr_warn("PHY interface mode was not setup. Set to MII.\n");
+               netdev_warn(ndev,
+                           "PHY interface mode was not setup. Set to MII.\n");
                value = 0x1;
                break;
        }
@@ -852,7 +855,7 @@ static int sh_eth_check_reset(struct net_device *ndev)
                cnt--;
        }
        if (cnt <= 0) {
-               pr_err("Device reset failed\n");
+               netdev_err(ndev, "Device reset failed\n");
                ret = -ETIMEDOUT;
        }
        return ret;
@@ -1554,8 +1557,7 @@ ignore_link:
                /* Unused write back interrupt */
                if (intr_status & EESR_TABT) {  /* Transmit Abort int */
                        ndev->stats.tx_aborted_errors++;
-                       if (netif_msg_tx_err(mdp))
-                               dev_err(&ndev->dev, "Transmit Abort\n");
+                       netif_err(mdp, tx_err, ndev, "Transmit Abort\n");
                }
        }
 
@@ -1564,45 +1566,38 @@ ignore_link:
                if (intr_status & EESR_RFRMER) {
                        /* Receive Frame Overflow int */
                        ndev->stats.rx_frame_errors++;
-                       if (netif_msg_rx_err(mdp))
-                               dev_err(&ndev->dev, "Receive Abort\n");
+                       netif_err(mdp, rx_err, ndev, "Receive Abort\n");
                }
        }
 
        if (intr_status & EESR_TDE) {
                /* Transmit Descriptor Empty int */
                ndev->stats.tx_fifo_errors++;
-               if (netif_msg_tx_err(mdp))
-                       dev_err(&ndev->dev, "Transmit Descriptor Empty\n");
+               netif_err(mdp, tx_err, ndev, "Transmit Descriptor Empty\n");
        }
 
        if (intr_status & EESR_TFE) {
                /* FIFO under flow */
                ndev->stats.tx_fifo_errors++;
-               if (netif_msg_tx_err(mdp))
-                       dev_err(&ndev->dev, "Transmit FIFO Under flow\n");
+               netif_err(mdp, tx_err, ndev, "Transmit FIFO Under flow\n");
        }
 
        if (intr_status & EESR_RDE) {
                /* Receive Descriptor Empty int */
                ndev->stats.rx_over_errors++;
-
-               if (netif_msg_rx_err(mdp))
-                       dev_err(&ndev->dev, "Receive Descriptor Empty\n");
+               netif_err(mdp, rx_err, ndev, "Receive Descriptor Empty\n");
        }
 
        if (intr_status & EESR_RFE) {
                /* Receive FIFO Overflow int */
                ndev->stats.rx_fifo_errors++;
-               if (netif_msg_rx_err(mdp))
-                       dev_err(&ndev->dev, "Receive FIFO Overflow\n");
+               netif_err(mdp, rx_err, ndev, "Receive FIFO Overflow\n");
        }
 
        if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) {
                /* Address Error */
                ndev->stats.tx_fifo_errors++;
-               if (netif_msg_tx_err(mdp))
-                       dev_err(&ndev->dev, "Address Error\n");
+               netif_err(mdp, tx_err, ndev, "Address Error\n");
        }
 
        mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE;
@@ -1613,9 +1608,9 @@ ignore_link:
                u32 edtrr = sh_eth_read(ndev, EDTRR);
 
                /* dmesg */
-               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);
+               netdev_err(ndev, "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);
 
@@ -1660,9 +1655,9 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
                                     EESIPR);
                        __napi_schedule(&mdp->napi);
                } else {
-                       dev_warn(&ndev->dev,
-                                "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n",
-                                intr_status, intr_enable);
+                       netdev_warn(ndev,
+                                   "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n",
+                                   intr_status, intr_enable);
                }
        }
 
@@ -1761,27 +1756,42 @@ static void sh_eth_adjust_link(struct net_device *ndev)
 /* PHY init function */
 static int sh_eth_phy_init(struct net_device *ndev)
 {
+       struct device_node *np = ndev->dev.parent->of_node;
        struct sh_eth_private *mdp = netdev_priv(ndev);
-       char phy_id[MII_BUS_ID_SIZE + 3];
        struct phy_device *phydev = NULL;
 
-       snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
-                mdp->mii_bus->id, mdp->phy_id);
-
        mdp->link = 0;
        mdp->speed = 0;
        mdp->duplex = -1;
 
        /* Try connect to PHY */
-       phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
-                            mdp->phy_interface);
+       if (np) {
+               struct device_node *pn;
+
+               pn = of_parse_phandle(np, "phy-handle", 0);
+               phydev = of_phy_connect(ndev, pn,
+                                       sh_eth_adjust_link, 0,
+                                       mdp->phy_interface);
+
+               if (!phydev)
+                       phydev = ERR_PTR(-ENOENT);
+       } else {
+               char phy_id[MII_BUS_ID_SIZE + 3];
+
+               snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
+                        mdp->mii_bus->id, mdp->phy_id);
+
+               phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
+                                    mdp->phy_interface);
+       }
+
        if (IS_ERR(phydev)) {
-               dev_err(&ndev->dev, "phy_connect failed\n");
+               netdev_err(ndev, "failed to connect PHY\n");
                return PTR_ERR(phydev);
        }
 
-       dev_info(&ndev->dev, "attached PHY %d (IRQ %d) to driver %s\n",
-                phydev->addr, phydev->irq, phydev->drv->name);
+       netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n",
+                   phydev->addr, phydev->irq, phydev->drv->name);
 
        mdp->phydev = phydev;
 
@@ -1962,12 +1972,12 @@ static int sh_eth_set_ringparam(struct net_device *ndev,
 
        ret = sh_eth_ring_init(ndev);
        if (ret < 0) {
-               dev_err(&ndev->dev, "%s: sh_eth_ring_init failed.\n", __func__);
+               netdev_err(ndev, "%s: sh_eth_ring_init failed.\n", __func__);
                return ret;
        }
        ret = sh_eth_dev_init(ndev, false);
        if (ret < 0) {
-               dev_err(&ndev->dev, "%s: sh_eth_dev_init failed.\n", __func__);
+               netdev_err(ndev, "%s: sh_eth_dev_init failed.\n", __func__);
                return ret;
        }
 
@@ -2008,7 +2018,7 @@ static int sh_eth_open(struct net_device *ndev)
        ret = request_irq(ndev->irq, sh_eth_interrupt,
                          mdp->cd->irq_flags, ndev->name, ndev);
        if (ret) {
-               dev_err(&ndev->dev, "Can not assign IRQ number\n");
+               netdev_err(ndev, "Can not assign IRQ number\n");
                goto out_napi_off;
        }
 
@@ -2046,10 +2056,9 @@ static void sh_eth_tx_timeout(struct net_device *ndev)
 
        netif_stop_queue(ndev);
 
-       if (netif_msg_timer(mdp)) {
-               dev_err(&ndev->dev, "%s: transmit timed out, status %8.8x, resetting...\n",
-                       ndev->name, (int)sh_eth_read(ndev, EESR));
-       }
+       netif_err(mdp, timer, ndev,
+                 "transmit timed out, status %8.8x, resetting...\n",
+                 (int)sh_eth_read(ndev, EESR));
 
        /* tx_errors count up */
        ndev->stats.tx_errors++;
@@ -2084,8 +2093,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        spin_lock_irqsave(&mdp->lock, flags);
        if ((mdp->cur_tx - mdp->dirty_tx) >= (mdp->num_tx_ring - 4)) {
                if (!sh_eth_txfree(ndev)) {
-                       if (netif_msg_tx_queued(mdp))
-                               dev_warn(&ndev->dev, "TxFD exhausted.\n");
+                       netif_warn(mdp, tx_queued, ndev, "TxFD exhausted.\n");
                        netif_stop_queue(ndev);
                        spin_unlock_irqrestore(&mdp->lock, flags);
                        return NETDEV_TX_BUSY;
@@ -2255,7 +2263,7 @@ static int sh_eth_tsu_busy(struct net_device *ndev)
                udelay(10);
                timeout--;
                if (timeout <= 0) {
-                       dev_err(&ndev->dev, "%s: timeout\n", __func__);
+                       netdev_err(ndev, "%s: timeout\n", __func__);
                        return -ETIMEDOUT;
                }
        }
@@ -2638,13 +2646,19 @@ static int sh_mdio_init(struct net_device *ndev, int id,
                goto out_free_bus;
        }
 
-       for (i = 0; i < PHY_MAX_ADDR; i++)
-               mdp->mii_bus->irq[i] = PHY_POLL;
-       if (pd->phy_irq > 0)
-               mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
-
        /* register mdio bus */
-       ret = mdiobus_register(mdp->mii_bus);
+       if (ndev->dev.parent->of_node) {
+               ret = of_mdiobus_register(mdp->mii_bus,
+                                         ndev->dev.parent->of_node);
+       } else {
+               for (i = 0; i < PHY_MAX_ADDR; i++)
+                       mdp->mii_bus->irq[i] = PHY_POLL;
+               if (pd->phy_irq > 0)
+                       mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
+
+               ret = mdiobus_register(mdp->mii_bus);
+       }
+
        if (ret)
                goto out_free_bus;
 
@@ -2680,7 +2694,6 @@ static const u16 *sh_eth_get_register_offset(int register_type)
                reg_offset = sh_eth_offset_fast_sh3_sh2;
                break;
        default:
-               pr_err("Unknown register type (%d)\n", register_type);
                break;
        }
 
@@ -2719,7 +2732,6 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
 {
        struct device_node *np = dev->of_node;
        struct sh_eth_plat_data *pdata;
-       struct device_node *phy;
        const char *mac_addr;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -2728,11 +2740,6 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
 
        pdata->phy_interface = of_get_phy_mode(np);
 
-       phy = of_parse_phandle(np, "phy-handle", 0);
-       if (of_property_read_u32(phy, "reg", &pdata->phy))
-               return NULL;
-       pdata->phy_irq = irq_of_parse_and_map(phy, 0);
-
        mac_addr = of_get_mac_address(np);
        if (mac_addr)
                memcpy(pdata->mac_addr, mac_addr, ETH_ALEN);
@@ -2842,6 +2849,12 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
                mdp->cd = (struct sh_eth_cpu_data *)match->data;
        }
        mdp->reg_offset = sh_eth_get_register_offset(mdp->cd->register_type);
+       if (!mdp->reg_offset) {
+               dev_err(&pdev->dev, "Unknown register type (%d)\n",
+                       mdp->cd->register_type);
+               ret = -EINVAL;
+               goto out_release;
+       }
        sh_eth_set_default_cpu_data(mdp->cd);
 
        /* set function */
@@ -2896,12 +2909,14 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
 
        /* mdio bus init */
        ret = sh_mdio_init(ndev, pdev->id, pd);
-       if (ret)
+       if (ret) {
+               dev_err(&ndev->dev, "failed to initialise MDIO\n");
                goto out_unregister;
+       }
 
        /* print device information */
-       pr_info("Base address at 0x%x, %pM, IRQ %d.\n",
-               (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
+       netdev_info(ndev, "Base address at 0x%x, %pM, IRQ %d.\n",
+                   (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
 
        platform_set_drvdata(pdev, ndev);
 
index 3b397987119de13cd67c5c4b419ce1955f108b36..651626e133f9b788dacc47234822c6f90190799d 100644 (file)
@@ -162,8 +162,8 @@ static int efx_ef10_get_mac_address(struct efx_nic *efx, u8 *mac_address)
        if (outlen < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)
                return -EIO;
 
-       memcpy(mac_address,
-              MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE), ETH_ALEN);
+       ether_addr_copy(mac_address,
+                       MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE));
        return 0;
 }
 
@@ -1955,6 +1955,9 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota)
        int tx_descs = 0;
        int spent = 0;
 
+       if (quota <= 0)
+               return spent;
+
        read_ptr = channel->eventq_read_ptr;
 
        for (;;) {
@@ -3145,12 +3148,10 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
                table->dev_uc_count = -1;
        } else {
                table->dev_uc_count = 1 + netdev_uc_count(net_dev);
-               memcpy(table->dev_uc_list[0].addr, net_dev->dev_addr,
-                      ETH_ALEN);
+               ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr);
                i = 1;
                netdev_for_each_uc_addr(uc, net_dev) {
-                       memcpy(table->dev_uc_list[i].addr,
-                              uc->addr, ETH_ALEN);
+                       ether_addr_copy(table->dev_uc_list[i].addr, uc->addr);
                        i++;
                }
        }
@@ -3162,8 +3163,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
                eth_broadcast_addr(table->dev_mc_list[0].addr);
                i = 1;
                netdev_for_each_mc_addr(mc, net_dev) {
-                       memcpy(table->dev_mc_list[i].addr,
-                              mc->addr, ETH_ALEN);
+                       ether_addr_copy(table->dev_mc_list[i].addr, mc->addr);
                        i++;
                }
        }
index d72e0038a7408d2dfeb8e817e618aff82c7a2a07..52589f6a8beb8d787185a708a050b9d1e28460c0 100644 (file)
@@ -1012,7 +1012,7 @@ static int efx_probe_port(struct efx_nic *efx)
                return rc;
 
        /* Initialise MAC address to permanent address */
-       memcpy(efx->net_dev->dev_addr, efx->net_dev->perm_addr, ETH_ALEN);
+       ether_addr_copy(efx->net_dev->dev_addr, efx->net_dev->perm_addr);
 
        return 0;
 }
@@ -2120,7 +2120,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
                return -EADDRNOTAVAIL;
        }
 
-       memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
+       ether_addr_copy(net_dev->dev_addr, new_addr);
        efx_sriov_mac_address_changed(efx);
 
        /* Reconfigure the MAC */
index 89fcaffd7de239215e6e02b0c3f93708396d957c..0de8b07c24c2bf39cd62a06021a42c217a3cba4c 100644 (file)
@@ -727,7 +727,7 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
 }
 
 /* MAC address mask including only I/G bit */
-static const u8 mac_addr_ig_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
+static const u8 mac_addr_ig_mask[ETH_ALEN] __aligned(2) = {0x01, 0, 0, 0, 0, 0};
 
 #define IP4_ADDR_FULL_MASK     ((__force __be32)~0)
 #define PORT_FULL_MASK         ((__force __be16)~0)
@@ -787,16 +787,16 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
                rule->flow_type = ETHER_FLOW;
                if (spec.match_flags &
                    (EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) {
-                       memcpy(mac_entry->h_dest, spec.loc_mac, ETH_ALEN);
+                       ether_addr_copy(mac_entry->h_dest, spec.loc_mac);
                        if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC)
-                               memset(mac_mask->h_dest, ~0, ETH_ALEN);
+                               eth_broadcast_addr(mac_mask->h_dest);
                        else
-                               memcpy(mac_mask->h_dest, mac_addr_ig_mask,
-                                      ETH_ALEN);
+                               ether_addr_copy(mac_mask->h_dest,
+                                               mac_addr_ig_mask);
                }
                if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) {
-                       memcpy(mac_entry->h_source, spec.rem_mac, ETH_ALEN);
-                       memset(mac_mask->h_source, ~0, ETH_ALEN);
+                       ether_addr_copy(mac_entry->h_source, spec.rem_mac);
+                       eth_broadcast_addr(mac_mask->h_source);
                }
                if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) {
                        mac_entry->h_proto = spec.ether_type;
@@ -968,13 +968,13 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
                                spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC;
                        else
                                return -EINVAL;
-                       memcpy(spec.loc_mac, mac_entry->h_dest, ETH_ALEN);
+                       ether_addr_copy(spec.loc_mac, mac_entry->h_dest);
                }
                if (!is_zero_ether_addr(mac_mask->h_source)) {
                        if (!is_broadcast_ether_addr(mac_mask->h_source))
                                return -EINVAL;
                        spec.match_flags |= EFX_FILTER_MATCH_REM_MAC;
-                       memcpy(spec.rem_mac, mac_entry->h_source, ETH_ALEN);
+                       ether_addr_copy(spec.rem_mac, mac_entry->h_source);
                }
                if (mac_mask->h_proto) {
                        if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK)
index 72652f380243adc9eaf93e0e565a14e203854279..8ec20b713cc610422781facd45c3c1a03c664164 100644 (file)
@@ -2183,7 +2183,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
        }
 
        /* Read the MAC addresses */
-       memcpy(efx->net_dev->perm_addr, nvconfig->mac_address[0], ETH_ALEN);
+       ether_addr_copy(efx->net_dev->perm_addr, nvconfig->mac_address[0]);
 
        netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n",
                  efx->phy_type, efx->mdio.prtad);
index aa1b169f45ec1fec4c989443bc493d8c03ea080e..a08761360cdf526caf33051142149c2962a17f6c 100644 (file)
@@ -1248,6 +1248,9 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget)
        int tx_packets = 0;
        int spent = 0;
 
+       if (budget <= 0)
+               return spent;
+
        read_ptr = channel->eventq_read_ptr;
 
        for (;;) {
index 3ef298d3c47e3b32078550231fccc46094cbef68..d0ed7f71ea7e25145bb4cf12395154efc587c3a0 100644 (file)
@@ -243,7 +243,7 @@ static inline int efx_filter_set_eth_local(struct efx_filter_spec *spec,
        }
        if (addr != NULL) {
                spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC;
-               memcpy(spec->loc_mac, addr, ETH_ALEN);
+               ether_addr_copy(spec->loc_mac, addr);
        }
        return 0;
 }
index eb59abb57e8506b4fc9605cad9fcb460be0625a3..7bd4b14bf3b32f627457eb1c48f6231922838670 100644 (file)
@@ -1187,6 +1187,9 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
        int rc;
 
        BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0);
+       /* we need __aligned(2) for ether_addr_copy */
+       BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST & 1);
+       BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST & 1);
 
        rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0,
                          outbuf, sizeof(outbuf), &outlen);
@@ -1199,11 +1202,10 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
        }
 
        if (mac_address)
-               memcpy(mac_address,
-                      port_num ?
-                      MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
-                      MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0),
-                      ETH_ALEN);
+               ether_addr_copy(mac_address,
+                               port_num ?
+                               MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
+                               MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0));
        if (fw_subtype_list) {
                for (i = 0;
                     i < MCDI_VAR_ARRAY_LEN(outlen,
@@ -1532,7 +1534,7 @@ static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
        MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type);
        MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE,
                       MC_CMD_FILTER_MODE_SIMPLE);
-       memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN);
+       ether_addr_copy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac);
 
        rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf),
                          outbuf, sizeof(outbuf), &outlen);
index 91d23252f8fae96d4ff4884d60b04a0cd5486750..e5fc4e1574b53f977e8509652aeb67e7404ca757 100644 (file)
@@ -854,8 +854,8 @@ int efx_mcdi_set_mac(struct efx_nic *efx)
 
        BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0);
 
-       memcpy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR),
-              efx->net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR),
+                       efx->net_dev->dev_addr);
 
        MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU,
                        EFX_MAX_FRAME_LEN(efx->net_dev->mtu));
index 28275e395cb87885649e44145f3bc9bb07a7f7b0..722344fcd155f095fbfcd39ba2e4aa960d31a1f4 100644 (file)
@@ -1652,6 +1652,13 @@ void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev)
        struct efx_ptp_data *ptp = efx->ptp_data;
        int code = EFX_QWORD_FIELD(*ev, MCDI_EVENT_CODE);
 
+       if (!ptp) {
+               if (net_ratelimit())
+                       netif_warn(efx, drv, efx->net_dev,
+                                  "Received PTP event but PTP not set up\n");
+               return;
+       }
+
        if (!ptp->enabled)
                return;
 
index 26641817a9c73ab6634057faaa93cba9f91ece0d..0fc5baef45b17377faeef424dab5217bb41a87a0 100644 (file)
@@ -50,7 +50,7 @@ struct efx_loopback_payload {
 } __packed;
 
 /* Loopback test source MAC address */
-static const unsigned char payload_source[ETH_ALEN] = {
+static const u8 payload_source[ETH_ALEN] __aligned(2) = {
        0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b,
 };
 
@@ -366,8 +366,8 @@ static void efx_iterate_state(struct efx_nic *efx)
        struct efx_loopback_payload *payload = &state->payload;
 
        /* Initialise the layerII header */
-       memcpy(&payload->header.h_dest, net_dev->dev_addr, ETH_ALEN);
-       memcpy(&payload->header.h_source, &payload_source, ETH_ALEN);
+       ether_addr_copy((u8 *)&payload->header.h_dest, net_dev->dev_addr);
+       ether_addr_copy((u8 *)&payload->header.h_source, payload_source);
        payload->header.h_proto = htons(ETH_P_IP);
 
        /* saddr set later and used as incrementing count */
index 0c38f926871ebbc99593cf71d263ae54cf83636c..9a9205e778964186d09094128a933179926f8006 100644 (file)
@@ -1095,7 +1095,7 @@ static void efx_sriov_peer_work(struct work_struct *data)
 
        /* Fill the remaining addresses */
        list_for_each_entry(local_addr, &efx->local_addr_list, link) {
-               memcpy(peer->mac_addr, local_addr->addr, ETH_ALEN);
+               ether_addr_copy(peer->mac_addr, local_addr->addr);
                peer->tci = 0;
                ++peer;
                ++peer_count;
@@ -1303,8 +1303,7 @@ int efx_sriov_init(struct efx_nic *efx)
                goto fail_vfs;
 
        rtnl_lock();
-       memcpy(vfdi_status->peers[0].mac_addr,
-              net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(vfdi_status->peers[0].mac_addr, net_dev->dev_addr);
        efx->vf_init_count = efx->vf_count;
        rtnl_unlock();
 
@@ -1452,8 +1451,8 @@ void efx_sriov_mac_address_changed(struct efx_nic *efx)
 
        if (!efx->vf_init_count)
                return;
-       memcpy(vfdi_status->peers[0].mac_addr,
-              efx->net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(vfdi_status->peers[0].mac_addr,
+                       efx->net_dev->dev_addr);
        queue_work(vfdi_workqueue, &efx->peer_work);
 }
 
@@ -1570,7 +1569,7 @@ int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
        vf = efx->vf + vf_i;
 
        mutex_lock(&vf->status_lock);
-       memcpy(vf->addr.mac_addr, mac, ETH_ALEN);
+       ether_addr_copy(vf->addr.mac_addr, mac);
        __efx_sriov_update_vf_addr(vf);
        mutex_unlock(&vf->status_lock);
 
@@ -1633,7 +1632,7 @@ int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
        vf = efx->vf + vf_i;
 
        ivi->vf = vf_i;
-       memcpy(ivi->mac, vf->addr.mac_addr, ETH_ALEN);
+       ether_addr_copy(ivi->mac, vf->addr.mac_addr);
        ivi->tx_rate = 0;
        tci = ntohs(vf->addr.tci);
        ivi->vlan = tci & VLAN_VID_MASK;
index 72d282bf33a51e8e2cb0036cac6fd03fe19acdf0..c553f6b5a9131f0af16230f59ccd0557fe1116a5 100644 (file)
@@ -151,7 +151,7 @@ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
                                          sizeof(struct dma_desc)));
 }
 
-const struct stmmac_chain_mode_ops chain_mode_ops = {
+const struct stmmac_mode_ops chain_mode_ops = {
        .init = stmmac_init_dma_chain,
        .is_jumbo_frm = stmmac_is_jumbo_frm,
        .jumbo_frm = stmmac_jumbo_frm,
index 7834a39939464a844fd4fd8bf8ecbc2f9f8847c0..74610f3aca9e5bc8670c49f4a25901c4b4575136 100644 (file)
@@ -419,20 +419,13 @@ struct mii_regs {
        unsigned int data;      /* MII Data */
 };
 
-struct stmmac_ring_mode_ops {
-       unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
-       unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
-       void (*refill_desc3) (void *priv, struct dma_desc *p);
-       void (*init_desc3) (struct dma_desc *p);
-       void (*clean_desc3) (void *priv, struct dma_desc *p);
-       int (*set_16kib_bfsize) (int mtu);
-};
-
-struct stmmac_chain_mode_ops {
+struct stmmac_mode_ops {
        void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
                      unsigned int extend_desc);
        unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
        unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+       int (*set_16kib_bfsize)(int mtu);
+       void (*init_desc3)(struct dma_desc *p);
        void (*refill_desc3) (void *priv, struct dma_desc *p);
        void (*clean_desc3) (void *priv, struct dma_desc *p);
 };
@@ -441,8 +434,7 @@ struct mac_device_info {
        const struct stmmac_ops *mac;
        const struct stmmac_desc_ops *desc;
        const struct stmmac_dma_ops *dma;
-       const struct stmmac_ring_mode_ops *ring;
-       const struct stmmac_chain_mode_ops *chain;
+       const struct stmmac_mode_ops *mode;
        const struct stmmac_hwtimestamp *ptp;
        struct mii_regs mii;    /* MII register Addresses */
        struct mac_link link;
@@ -460,7 +452,7 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
 void stmmac_set_mac(void __iomem *ioaddr, bool enable);
 
 void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
-extern const struct stmmac_ring_mode_ops ring_mode_ops;
-extern const struct stmmac_chain_mode_ops chain_mode_ops;
+extern const struct stmmac_mode_ops ring_mode_ops;
+extern const struct stmmac_mode_ops chain_mode_ops;
 
 #endif /* __COMMON_H__ */
index a96c7c2f5f3f220b32df9c0ebad2b197e7ecd45a..650a4be6bce5243e046fcd226719e669f66444e8 100644 (file)
@@ -100,10 +100,9 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
 {
        struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
 
-       if (unlikely(priv->plat->has_gmac))
-               /* Fill DES3 in case of RING mode */
-               if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
-                       p->des3 = p->des2 + BUF_SIZE_8KiB;
+       /* Fill DES3 in case of RING mode */
+       if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
+               p->des3 = p->des2 + BUF_SIZE_8KiB;
 }
 
 /* In ring mode we need to fill the desc3 because it is used as buffer */
@@ -126,7 +125,7 @@ static int stmmac_set_16kib_bfsize(int mtu)
        return ret;
 }
 
-const struct stmmac_ring_mode_ops ring_mode_ops = {
+const struct stmmac_mode_ops ring_mode_ops = {
        .is_jumbo_frm = stmmac_is_jumbo_frm,
        .jumbo_frm = stmmac_jumbo_frm,
        .refill_desc3 = stmmac_refill_desc3,
index a2e7d2c96e3678c309377d3e4dbb416feb5fbc38..8543e1cfd55edb4a60f5cb543a1e5ea9fc18a097 100644 (file)
@@ -92,8 +92,8 @@ static int tc = TC_DEFAULT;
 module_param(tc, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(tc, "DMA threshold control value");
 
-#define DMA_BUFFER_SIZE        BUF_SIZE_4KiB
-static int buf_sz = DMA_BUFFER_SIZE;
+#define        DEFAULT_BUFSIZE 1536
+static int buf_sz = DEFAULT_BUFSIZE;
 module_param(buf_sz, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(buf_sz, "DMA buffer size");
 
@@ -136,8 +136,8 @@ static void stmmac_verify_args(void)
                dma_rxsize = DMA_RX_SIZE;
        if (unlikely(dma_txsize < 0))
                dma_txsize = DMA_TX_SIZE;
-       if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB)))
-               buf_sz = DMA_BUFFER_SIZE;
+       if (unlikely((buf_sz < DEFAULT_BUFSIZE) || (buf_sz > BUF_SIZE_16KiB)))
+               buf_sz = DEFAULT_BUFSIZE;
        if (unlikely(flow_ctrl > 1))
                flow_ctrl = FLOW_AUTO;
        else if (likely(flow_ctrl < 0))
@@ -286,10 +286,25 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 
        /* MAC core supports the EEE feature. */
        if (priv->dma_cap.eee) {
+               int tx_lpi_timer = priv->tx_lpi_timer;
+
                /* Check if the PHY supports EEE */
-               if (phy_init_eee(priv->phydev, 1))
+               if (phy_init_eee(priv->phydev, 1)) {
+                       /* To manage at run-time if the EEE cannot be supported
+                        * anymore (for example because the lp caps have been
+                        * changed).
+                        * In that case the driver disable own timers.
+                        */
+                       if (priv->eee_active) {
+                               pr_debug("stmmac: disable EEE\n");
+                               del_timer_sync(&priv->eee_ctrl_timer);
+                               priv->hw->mac->set_eee_timer(priv->ioaddr, 0,
+                                                            tx_lpi_timer);
+                       }
+                       priv->eee_active = 0;
                        goto out;
-
+               }
+               /* Activate the EEE and start timers */
                if (!priv->eee_active) {
                        priv->eee_active = 1;
                        init_timer(&priv->eee_ctrl_timer);
@@ -300,13 +315,13 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 
                        priv->hw->mac->set_eee_timer(priv->ioaddr,
                                                     STMMAC_DEFAULT_LIT_LS,
-                                                    priv->tx_lpi_timer);
+                                                    tx_lpi_timer);
                } else
                        /* Set HW EEE according to the speed */
                        priv->hw->mac->set_eee_pls(priv->ioaddr,
                                                   priv->phydev->link);
 
-               pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
+               pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
 
                ret = true;
        }
@@ -886,10 +901,10 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
                ret = BUF_SIZE_8KiB;
        else if (mtu >= BUF_SIZE_2KiB)
                ret = BUF_SIZE_4KiB;
-       else if (mtu >= DMA_BUFFER_SIZE)
+       else if (mtu > DEFAULT_BUFSIZE)
                ret = BUF_SIZE_2KiB;
        else
-               ret = DMA_BUFFER_SIZE;
+               ret = DEFAULT_BUFSIZE;
 
        return ret;
 }
@@ -951,9 +966,9 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
 
        p->des2 = priv->rx_skbuff_dma[i];
 
-       if ((priv->mode == STMMAC_RING_MODE) &&
+       if ((priv->hw->mode->init_desc3) &&
            (priv->dma_buf_sz == BUF_SIZE_16KiB))
-               priv->hw->ring->init_desc3(p);
+               priv->hw->mode->init_desc3(p);
 
        return 0;
 }
@@ -984,11 +999,8 @@ static int init_dma_desc_rings(struct net_device *dev)
        unsigned int bfsize = 0;
        int ret = -ENOMEM;
 
-       /* Set the max buffer size according to the DESC mode
-        * and the MTU. Note that RING mode allows 16KiB bsize.
-        */
-       if (priv->mode == STMMAC_RING_MODE)
-               bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
+       if (priv->hw->mode->set_16kib_bfsize)
+               bfsize = priv->hw->mode->set_16kib_bfsize(dev->mtu);
 
        if (bfsize < BUF_SIZE_16KiB)
                bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
@@ -1029,15 +1041,15 @@ static int init_dma_desc_rings(struct net_device *dev)
        /* Setup the chained descriptor addresses */
        if (priv->mode == STMMAC_CHAIN_MODE) {
                if (priv->extend_desc) {
-                       priv->hw->chain->init(priv->dma_erx, priv->dma_rx_phy,
-                                             rxsize, 1);
-                       priv->hw->chain->init(priv->dma_etx, priv->dma_tx_phy,
-                                             txsize, 1);
+                       priv->hw->mode->init(priv->dma_erx, priv->dma_rx_phy,
+                                            rxsize, 1);
+                       priv->hw->mode->init(priv->dma_etx, priv->dma_tx_phy,
+                                            txsize, 1);
                } else {
-                       priv->hw->chain->init(priv->dma_rx, priv->dma_rx_phy,
-                                             rxsize, 0);
-                       priv->hw->chain->init(priv->dma_tx, priv->dma_tx_phy,
-                                             txsize, 0);
+                       priv->hw->mode->init(priv->dma_rx, priv->dma_rx_phy,
+                                            rxsize, 0);
+                       priv->hw->mode->init(priv->dma_tx, priv->dma_tx_phy,
+                                            txsize, 0);
                }
        }
 
@@ -1288,7 +1300,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
                                         DMA_TO_DEVICE);
                        priv->tx_skbuff_dma[entry] = 0;
                }
-               priv->hw->ring->clean_desc3(priv, p);
+               priv->hw->mode->clean_desc3(priv, p);
 
                if (likely(skb != NULL)) {
                        dev_kfree_skb(skb);
@@ -1705,7 +1717,7 @@ static int stmmac_open(struct net_device *dev)
        priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
        priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
 
-       alloc_dma_desc_resources(priv);
+       ret = alloc_dma_desc_resources(priv);
        if (ret < 0) {
                pr_err("%s: DMA descriptors allocation failed\n", __func__);
                goto dma_desc_error;
@@ -1844,6 +1856,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        int nfrags = skb_shinfo(skb)->nr_frags;
        struct dma_desc *desc, *first;
        unsigned int nopaged_len = skb_headlen(skb);
+       unsigned int enh_desc = priv->plat->enh_desc;
 
        if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
                if (!netif_queue_stopped(dev)) {
@@ -1871,27 +1884,19 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        first = desc;
 
        /* To program the descriptors according to the size of the frame */
-       if (priv->mode == STMMAC_RING_MODE) {
-               is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len,
-                                                       priv->plat->enh_desc);
-               if (unlikely(is_jumbo))
-                       entry = priv->hw->ring->jumbo_frm(priv, skb,
-                                                         csum_insertion);
-       } else {
-               is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len,
-                                                        priv->plat->enh_desc);
-               if (unlikely(is_jumbo))
-                       entry = priv->hw->chain->jumbo_frm(priv, skb,
-                                                          csum_insertion);
-       }
+       if (enh_desc)
+               is_jumbo = priv->hw->mode->is_jumbo_frm(skb->len, enh_desc);
+
        if (likely(!is_jumbo)) {
                desc->des2 = dma_map_single(priv->device, skb->data,
                                            nopaged_len, DMA_TO_DEVICE);
                priv->tx_skbuff_dma[entry] = desc->des2;
                priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
                                                csum_insertion, priv->mode);
-       } else
+       } else {
                desc = first;
+               entry = priv->hw->mode->jumbo_frm(priv, skb, csum_insertion);
+       }
 
        for (i = 0; i < nfrags; i++) {
                const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -2029,7 +2034,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
 
                        p->des2 = priv->rx_skbuff_dma[entry];
 
-                       priv->hw->ring->refill_desc3(priv, p);
+                       priv->hw->mode->refill_desc3(priv, p);
 
                        if (netif_msg_rx_status(priv))
                                pr_debug("\trefill entry #%d\n", entry);
@@ -2633,11 +2638,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
 
        /* To use the chained or ring mode */
        if (chain_mode) {
-               priv->hw->chain = &chain_mode_ops;
+               priv->hw->mode = &chain_mode_ops;
                pr_info(" Chain mode enabled\n");
                priv->mode = STMMAC_CHAIN_MODE;
        } else {
-               priv->hw->ring = &ring_mode_ops;
+               priv->hw->mode = &ring_mode_ops;
                pr_info(" Ring mode enabled\n");
                priv->mode = STMMAC_RING_MODE;
        }
index c61bc72b8e9006a2f8cb654421a7aaed50730436..8fb32a80f1c1999a18234a2daec7323affd3917a 100644 (file)
@@ -36,7 +36,7 @@ static const struct of_device_id stmmac_dt_ids[] = {
 #ifdef CONFIG_DWMAC_STI
        { .compatible = "st,stih415-dwmac", .data = &sti_gmac_data},
        { .compatible = "st,stih416-dwmac", .data = &sti_gmac_data},
-       { .compatible = "st,stih127-dwmac", .data = &sti_gmac_data},
+       { .compatible = "st,stid127-dwmac", .data = &sti_gmac_data},
 #endif
        /* SoC specific glue layers should come before generic bindings */
        { .compatible = "st,spear600-gmac"},
index 0b6a2802d51b24f18371f1b12ed37fca41bda0ff..543a0813c9e05d6b4b814c79becf9f49b0c8e539 100644 (file)
@@ -378,7 +378,6 @@ struct cpsw_priv {
        u32                             version;
        u32                             coal_intvl;
        u32                             bus_freq_mhz;
-       struct net_device_stats         stats;
        int                             rx_packet_max;
        int                             host_port;
        struct clk                      *clk;
@@ -673,8 +672,8 @@ static void cpsw_tx_handler(void *token, int len, int status)
        if (unlikely(netif_queue_stopped(ndev)))
                netif_wake_queue(ndev);
        cpts_tx_timestamp(priv->cpts, skb);
-       priv->stats.tx_packets++;
-       priv->stats.tx_bytes += len;
+       ndev->stats.tx_packets++;
+       ndev->stats.tx_bytes += len;
        dev_kfree_skb_any(skb);
 }
 
@@ -700,10 +699,10 @@ static void cpsw_rx_handler(void *token, int len, int status)
                cpts_rx_timestamp(priv->cpts, skb);
                skb->protocol = eth_type_trans(skb, ndev);
                netif_receive_skb(skb);
-               priv->stats.rx_bytes += len;
-               priv->stats.rx_packets++;
+               ndev->stats.rx_bytes += len;
+               ndev->stats.rx_packets++;
        } else {
-               priv->stats.rx_dropped++;
+               ndev->stats.rx_dropped++;
                new_skb = skb;
        }
 
@@ -1164,11 +1163,17 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
 
 static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
 {
+       u32 slave_port;
+
+       slave_port = cpsw_get_slave_port(priv, slave->slave_num);
+
        if (!slave->phy)
                return;
        phy_stop(slave->phy);
        phy_disconnect(slave->phy);
        slave->phy = NULL;
+       cpsw_ale_control_set(priv->ale, slave_port,
+                            ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
 }
 
 static int cpsw_ndo_open(struct net_device *ndev)
@@ -1307,7 +1312,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
 
        if (skb_padto(skb, CPSW_MIN_PACKET_SIZE)) {
                cpsw_err(priv, tx_err, "packet pad failed\n");
-               priv->stats.tx_dropped++;
+               ndev->stats.tx_dropped++;
                return NETDEV_TX_OK;
        }
 
@@ -1331,7 +1336,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
 
        return NETDEV_TX_OK;
 fail:
-       priv->stats.tx_dropped++;
+       ndev->stats.tx_dropped++;
        netif_stop_queue(ndev);
        return NETDEV_TX_BUSY;
 }
@@ -1495,7 +1500,7 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)
        struct cpsw_priv *priv = netdev_priv(ndev);
 
        cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n");
-       priv->stats.tx_errors++;
+       ndev->stats.tx_errors++;
        cpsw_intr_disable(priv);
        cpdma_ctlr_int_ctrl(priv->dma, false);
        cpdma_chan_stop(priv->txch);
@@ -1534,12 +1539,6 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p)
        return 0;
 }
 
-static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev)
-{
-       struct cpsw_priv *priv = netdev_priv(ndev);
-       return &priv->stats;
-}
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void cpsw_ndo_poll_controller(struct net_device *ndev)
 {
@@ -1632,7 +1631,6 @@ static const struct net_device_ops cpsw_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_change_mtu         = eth_change_mtu,
        .ndo_tx_timeout         = cpsw_ndo_tx_timeout,
-       .ndo_get_stats          = cpsw_ndo_get_stats,
        .ndo_set_rx_mode        = cpsw_ndo_set_rx_mode,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = cpsw_ndo_poll_controller,
index 17503da9f7a589d5f56484329179c4c68c4af429..b43f1b3b9632ad7574d8819d7c341c640bafc4eb 100644 (file)
@@ -659,6 +659,9 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
        struct info_mpipe *info_mpipe =
                container_of(napi, struct info_mpipe, napi);
 
+       if (budget <= 0)
+               goto done;
+
        instance = info_mpipe->instance;
        while ((n = gxio_mpipe_iqueue_try_peek(
                        &info_mpipe->iqueue,
index edb2e12a0fe214894e9a9a0445ccc7e869dbe7d6..b94449b4bd34f7a436bb2e251532254b712ac2d1 100644 (file)
@@ -831,6 +831,9 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
 
        unsigned int work = 0;
 
+       if (budget <= 0)
+               goto done;
+
        while (priv->active) {
                int index = qup->__packet_receive_read;
                if (index == qsp->__packet_receive_queue.__packet_write)
@@ -2068,14 +2071,14 @@ static struct rtnl_link_stats64 *tile_net_get_stats64(struct net_device *dev,
                cpu_stats = &priv->cpu[i]->stats;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&cpu_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
                        trx_packets = cpu_stats->rx_packets;
                        ttx_packets = cpu_stats->tx_packets;
                        trx_bytes   = cpu_stats->rx_bytes;
                        ttx_bytes   = cpu_stats->tx_bytes;
                        trx_errors  = cpu_stats->rx_errors;
                        trx_dropped = cpu_stats->rx_dropped;
-               } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
 
                rx_packets += trx_packets;
                tx_packets += ttx_packets;
index 88e9c73cebc015b9a31b169b973911f92ef8a9d8..fef5573dbfcac0f6db7c44be4124fd04c1fe6587 100644 (file)
@@ -1645,6 +1645,9 @@ static int tc35815_poll(struct napi_struct *napi, int budget)
        int received = 0, handled;
        u32 status;
 
+       if (budget <= 0)
+               return received;
+
        spin_lock(&lp->rx_lock);
        status = tc_readl(&tr->Int_Src);
        do {
index ef312bc6b8658deabae28d179c39237564b8ede4..5bc1a2d02dc125ebf78ba35a40012baa3f0715b9 100644 (file)
@@ -2070,16 +2070,16 @@ rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
        netdev_stats_to_stats64(stats, &dev->stats);
 
        do {
-               start = u64_stats_fetch_begin_bh(&rp->rx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&rp->rx_stats.syncp);
                stats->rx_packets = rp->rx_stats.packets;
                stats->rx_bytes = rp->rx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&rp->rx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&rp->rx_stats.syncp, start));
 
        do {
-               start = u64_stats_fetch_begin_bh(&rp->tx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&rp->tx_stats.syncp);
                stats->tx_packets = rp->tx_stats.packets;
                stats->tx_bytes = rp->tx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&rp->tx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&rp->tx_stats.syncp, start));
 
        return stats;
 }
index a4347508031ce4cff516c8d5dce32a4ba9e2efa8..fa193c4688da78719257ac982af8be1f81b270c1 100644 (file)
@@ -771,8 +771,8 @@ static void ll_temac_recv(struct net_device *ndev)
 
                /* if we're doing rx csum offload, set it up */
                if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) &&
-                       (skb->protocol == __constant_htons(ETH_P_IP)) &&
-                       (skb->len > 64)) {
+                   (skb->protocol == htons(ETH_P_IP)) &&
+                   (skb->len > 64)) {
 
                        skb->csum = cur_p->app3 & 0xFFFF;
                        skb->ip_summed = CHECKSUM_COMPLETE;
index 4bfdf8c7ada033cf964f1da66daba0137b499e6f..7b0a735562645cf042cfb312ace5018180d94559 100644 (file)
@@ -756,7 +756,7 @@ static void axienet_recv(struct net_device *ndev)
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
                        }
                } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 &&
-                          skb->protocol == __constant_htons(ETH_P_IP) &&
+                          skb->protocol == htons(ETH_P_IP) &&
                           skb->len > 64) {
                        skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF);
                        skb->ip_summed = CHECKSUM_COMPLETE;
index 39fc230f5c201cfdf4d7e1512dcc6e165b32ea70..13010b4dae5b7ddea9b3a48cf28dc8425c5b3e6c 100644 (file)
@@ -30,6 +30,7 @@
 
 /* Fwd declaration */
 struct hv_netvsc_packet;
+struct ndis_tcp_ip_checksum_info;
 
 /* Represent the xfer page packet which contains 1 or more netvsc packet */
 struct xferpage_packet {
@@ -73,7 +74,7 @@ struct hv_netvsc_packet {
        } completion;
 
        /* This points to the memory after page_buf */
-       void *extension;
+       struct rndis_message *rndis_msg;
 
        u32 total_data_buflen;
        /* Points to the send/receive buffer where the ethernet frame is */
@@ -117,7 +118,8 @@ int netvsc_send(struct hv_device *device,
 void netvsc_linkstatus_callback(struct hv_device *device_obj,
                                unsigned int status);
 int netvsc_recv_callback(struct hv_device *device_obj,
-                       struct hv_netvsc_packet *packet);
+                       struct hv_netvsc_packet *packet,
+                       struct ndis_tcp_ip_checksum_info *csum_info);
 int rndis_filter_open(struct hv_device *dev);
 int rndis_filter_close(struct hv_device *dev);
 int rndis_filter_device_add(struct hv_device *dev,
@@ -126,11 +128,6 @@ void rndis_filter_device_remove(struct hv_device *dev);
 int rndis_filter_receive(struct hv_device *dev,
                        struct hv_netvsc_packet *pkt);
 
-
-
-int rndis_filter_send(struct hv_device *dev,
-                       struct hv_netvsc_packet *pkt);
-
 int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
 int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
 
@@ -516,6 +513,7 @@ struct nvsp_message {
 #define NETVSC_MTU 65536
 
 #define NETVSC_RECEIVE_BUFFER_SIZE             (1024*1024*16)  /* 16MB */
+#define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY      (1024*1024*15)  /* 15MB */
 
 #define NETVSC_RECEIVE_BUFFER_ID               0xcafe
 
@@ -726,9 +724,133 @@ struct ndis_pkt_8021q_info {
        };
 };
 
+struct ndis_oject_header {
+       u8 type;
+       u8 revision;
+       u16 size;
+};
+
+#define NDIS_OBJECT_TYPE_DEFAULT       0x80
+#define NDIS_OFFLOAD_PARAMETERS_REVISION_3 3
+#define NDIS_OFFLOAD_PARAMETERS_NO_CHANGE 0
+#define NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED  2
+#define NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED  2
+#define NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3
+#define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4
+
+#define NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE    1
+#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4       0
+#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6       1
+
+/*
+ * New offload OIDs for NDIS 6
+ */
+#define OID_TCP_OFFLOAD_CURRENT_CONFIG 0xFC01020B /* query only */
+#define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C          /* set only */
+#define OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020D/* query only */
+#define OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG 0xFC01020E /* query only */
+#define OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020F /* query */
+#define OID_OFFLOAD_ENCAPSULATION 0x0101010A /* set/query */
+
+struct ndis_offload_params {
+       struct ndis_oject_header header;
+       u8 ip_v4_csum;
+       u8 tcp_ip_v4_csum;
+       u8 udp_ip_v4_csum;
+       u8 tcp_ip_v6_csum;
+       u8 udp_ip_v6_csum;
+       u8 lso_v1;
+       u8 ip_sec_v1;
+       u8 lso_v2_ipv4;
+       u8 lso_v2_ipv6;
+       u8 tcp_connection_ip_v4;
+       u8 tcp_connection_ip_v6;
+       u32 flags;
+       u8 ip_sec_v2;
+       u8 ip_sec_v2_ip_v4;
+       struct {
+               u8 rsc_ip_v4;
+               u8 rsc_ip_v6;
+       };
+       struct {
+               u8 encapsulated_packet_task_offload;
+               u8 encapsulation_types;
+       };
+};
+
+struct ndis_tcp_ip_checksum_info {
+       union {
+               struct {
+                       u32 is_ipv4:1;
+                       u32 is_ipv6:1;
+                       u32 tcp_checksum:1;
+                       u32 udp_checksum:1;
+                       u32 ip_header_checksum:1;
+                       u32 reserved:11;
+                       u32 tcp_header_offset:10;
+               } transmit;
+               struct {
+                       u32 tcp_checksum_failed:1;
+                       u32 udp_checksum_failed:1;
+                       u32 ip_checksum_failed:1;
+                       u32 tcp_checksum_succeeded:1;
+                       u32 udp_checksum_succeeded:1;
+                       u32 ip_checksum_succeeded:1;
+                       u32 loopback:1;
+                       u32 tcp_checksum_value_invalid:1;
+                       u32 ip_checksum_value_invalid:1;
+               } receive;
+               u32  value;
+       };
+};
+
+struct ndis_tcp_lso_info {
+       union {
+               struct {
+                       u32 unused:30;
+                       u32 type:1;
+                       u32 reserved2:1;
+               } transmit;
+               struct {
+                       u32 mss:20;
+                       u32 tcp_header_offset:10;
+                       u32 type:1;
+                       u32 reserved2:1;
+               } lso_v1_transmit;
+               struct {
+                       u32 tcp_payload:30;
+                       u32 type:1;
+                       u32 reserved2:1;
+               } lso_v1_transmit_complete;
+               struct {
+                       u32 mss:20;
+                       u32 tcp_header_offset:10;
+                       u32 type:1;
+                       u32 ip_version:1;
+               } lso_v2_transmit;
+               struct {
+                       u32 reserved:30;
+                       u32 type:1;
+                       u32 reserved2:1;
+               } lso_v2_transmit_complete;
+               u32  value;
+       };
+};
+
 #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
                sizeof(struct ndis_pkt_8021q_info))
 
+#define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
+               sizeof(struct ndis_tcp_ip_checksum_info))
+
+#define NDIS_LSO_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
+               sizeof(struct ndis_tcp_lso_info))
+
 /* Format of Information buffer passed in a SetRequest for the OID */
 /* OID_GEN_RNDIS_CONFIG_PARAMETER. */
 struct rndis_config_parameter_info {
@@ -954,6 +1076,16 @@ struct rndis_message {
 #define NDIS_PACKET_TYPE_FUNCTIONAL    0x00000400
 #define NDIS_PACKET_TYPE_MAC_FRAME     0x00000800
 
+#define INFO_IPV4       2
+#define INFO_IPV6       4
+#define INFO_TCP        2
+#define INFO_UDP        4
+
+#define TRANSPORT_INFO_NOT_IP   0
+#define TRANSPORT_INFO_IPV4_TCP ((INFO_IPV4 << 16) | INFO_TCP)
+#define TRANSPORT_INFO_IPV4_UDP ((INFO_IPV4 << 16) | INFO_UDP)
+#define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP)
+#define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP)
 
 
 #endif /* _HYPERV_NET_H */
index 1a0280dcba7e0d755cfa11ef5b3cabe6eede824e..daddea2654ce4ec6ee3e3db66d45c9edb9ceb35f 100644 (file)
@@ -365,6 +365,11 @@ static int netvsc_connect_vsp(struct hv_device *device)
                goto cleanup;
 
        /* Post the big receive buffer to NetVSP */
+       if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_2)
+               net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
+       else
+               net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
+
        ret = netvsc_init_recv_buf(device);
 
 cleanup:
@@ -898,7 +903,6 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
        ndev = net_device->ndev;
 
        /* Initialize the NetVSC channel extension */
-       net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
        spin_lock_init(&net_device->recv_pkt_list_lock);
 
        INIT_LIST_HEAD(&net_device->recv_pkt_list);
index 9ef6be90a81cf9e9cdadf08294e3e7fc40edf32a..4e4cf9e0c8d7a6c6472f2dee357b8b31a814c2b8 100644 (file)
@@ -128,6 +128,27 @@ static int netvsc_close(struct net_device *net)
        return ret;
 }
 
+static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,
+                               int pkt_type)
+{
+       struct rndis_packet *rndis_pkt;
+       struct rndis_per_packet_info *ppi;
+
+       rndis_pkt = &msg->msg.pkt;
+       rndis_pkt->data_offset += ppi_size;
+
+       ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt +
+               rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len);
+
+       ppi->size = ppi_size;
+       ppi->type = pkt_type;
+       ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
+
+       rndis_pkt->per_pkt_info_len += ppi_size;
+
+       return ppi;
+}
+
 static void netvsc_xmit_completion(void *context)
 {
        struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
@@ -140,21 +161,163 @@ static void netvsc_xmit_completion(void *context)
                dev_kfree_skb_any(skb);
 }
 
+static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
+                       struct hv_page_buffer *pb)
+{
+       int j = 0;
+
+       /* Deal with compund pages by ignoring unused part
+        * of the page.
+        */
+       page += (offset >> PAGE_SHIFT);
+       offset &= ~PAGE_MASK;
+
+       while (len > 0) {
+               unsigned long bytes;
+
+               bytes = PAGE_SIZE - offset;
+               if (bytes > len)
+                       bytes = len;
+               pb[j].pfn = page_to_pfn(page);
+               pb[j].offset = offset;
+               pb[j].len = bytes;
+
+               offset += bytes;
+               len -= bytes;
+
+               if (offset == PAGE_SIZE && len) {
+                       page++;
+                       offset = 0;
+                       j++;
+               }
+       }
+
+       return j + 1;
+}
+
+static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
+                          struct hv_page_buffer *pb)
+{
+       u32 slots_used = 0;
+       char *data = skb->data;
+       int frags = skb_shinfo(skb)->nr_frags;
+       int i;
+
+       /* The packet is laid out thus:
+        * 1. hdr
+        * 2. skb linear data
+        * 3. skb fragment data
+        */
+       if (hdr != NULL)
+               slots_used += fill_pg_buf(virt_to_page(hdr),
+                                       offset_in_page(hdr),
+                                       len, &pb[slots_used]);
+
+       slots_used += fill_pg_buf(virt_to_page(data),
+                               offset_in_page(data),
+                               skb_headlen(skb), &pb[slots_used]);
+
+       for (i = 0; i < frags; i++) {
+               skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+               slots_used += fill_pg_buf(skb_frag_page(frag),
+                                       frag->page_offset,
+                                       skb_frag_size(frag), &pb[slots_used]);
+       }
+       return slots_used;
+}
+
+static int count_skb_frag_slots(struct sk_buff *skb)
+{
+       int i, frags = skb_shinfo(skb)->nr_frags;
+       int pages = 0;
+
+       for (i = 0; i < frags; i++) {
+               skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+               unsigned long size = skb_frag_size(frag);
+               unsigned long offset = frag->page_offset;
+
+               /* Skip unused frames from start of page */
+               offset &= ~PAGE_MASK;
+               pages += PFN_UP(offset + size);
+       }
+       return pages;
+}
+
+static int netvsc_get_slots(struct sk_buff *skb)
+{
+       char *data = skb->data;
+       unsigned int offset = offset_in_page(data);
+       unsigned int len = skb_headlen(skb);
+       int slots;
+       int frag_slots;
+
+       slots = DIV_ROUND_UP(offset + len, PAGE_SIZE);
+       frag_slots = count_skb_frag_slots(skb);
+       return slots + frag_slots;
+}
+
+static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off)
+{
+       u32 ret_val = TRANSPORT_INFO_NOT_IP;
+
+       if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) &&
+               (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) {
+               goto not_ip;
+       }
+
+       *trans_off = skb_transport_offset(skb);
+
+       if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) {
+               struct iphdr *iphdr = ip_hdr(skb);
+
+               if (iphdr->protocol == IPPROTO_TCP)
+                       ret_val = TRANSPORT_INFO_IPV4_TCP;
+               else if (iphdr->protocol == IPPROTO_UDP)
+                       ret_val = TRANSPORT_INFO_IPV4_UDP;
+       } else {
+               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+                       ret_val = TRANSPORT_INFO_IPV6_TCP;
+               else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
+                       ret_val = TRANSPORT_INFO_IPV6_UDP;
+       }
+
+not_ip:
+       return ret_val;
+}
+
 static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
 {
        struct net_device_context *net_device_ctx = netdev_priv(net);
        struct hv_netvsc_packet *packet;
        int ret;
-       unsigned int i, num_pages, npg_data;
-
-       /* Add multipages for skb->data and additional 2 for RNDIS */
-       npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1)
-               >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1;
-       num_pages = skb_shinfo(skb)->nr_frags + npg_data + 2;
+       unsigned int num_data_pgs;
+       struct rndis_message *rndis_msg;
+       struct rndis_packet *rndis_pkt;
+       u32 rndis_msg_size;
+       bool isvlan;
+       struct rndis_per_packet_info *ppi;
+       struct ndis_tcp_ip_checksum_info *csum_info;
+       struct ndis_tcp_lso_info *lso_info;
+       int  hdr_offset;
+       u32 net_trans_info;
+
+
+       /* We will atmost need two pages to describe the rndis
+        * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
+        * of pages in a single packet.
+        */
+       num_data_pgs = netvsc_get_slots(skb) + 2;
+       if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
+               netdev_err(net, "Packet too big: %u\n", skb->len);
+               dev_kfree_skb(skb);
+               net->stats.tx_dropped++;
+               return NETDEV_TX_OK;
+       }
 
        /* Allocate a netvsc packet based on # of frags. */
        packet = kzalloc(sizeof(struct hv_netvsc_packet) +
-                        (num_pages * sizeof(struct hv_page_buffer)) +
+                        (num_data_pgs * sizeof(struct hv_page_buffer)) +
                         sizeof(struct rndis_message) +
                         NDIS_VLAN_PPI_SIZE, GFP_ATOMIC);
        if (!packet) {
@@ -168,53 +331,111 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
 
        packet->vlan_tci = skb->vlan_tci;
 
-       packet->extension = (void *)(unsigned long)packet +
+       packet->is_data_pkt = true;
+       packet->total_data_buflen = skb->len;
+
+       packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
                                sizeof(struct hv_netvsc_packet) +
-                                   (num_pages * sizeof(struct hv_page_buffer));
+                               (num_data_pgs * sizeof(struct hv_page_buffer)));
 
-       /* If the rndis msg goes beyond 1 page, we will add 1 later */
-       packet->page_buf_cnt = num_pages - 1;
+       /* Set the completion routine */
+       packet->completion.send.send_completion = netvsc_xmit_completion;
+       packet->completion.send.send_completion_ctx = packet;
+       packet->completion.send.send_completion_tid = (unsigned long)skb;
 
-       /* Initialize it from the skb */
-       packet->total_data_buflen = skb->len;
+       isvlan = packet->vlan_tci & VLAN_TAG_PRESENT;
+
+       /* Add the rndis header */
+       rndis_msg = packet->rndis_msg;
+       rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
+       rndis_msg->msg_len = packet->total_data_buflen;
+       rndis_pkt = &rndis_msg->msg.pkt;
+       rndis_pkt->data_offset = sizeof(struct rndis_packet);
+       rndis_pkt->data_len = packet->total_data_buflen;
+       rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
+
+       rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
+
+       if (isvlan) {
+               struct ndis_pkt_8021q_info *vlan;
+
+               rndis_msg_size += NDIS_VLAN_PPI_SIZE;
+               ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE,
+                                       IEEE_8021Q_INFO);
+               vlan = (struct ndis_pkt_8021q_info *)((void *)ppi +
+                                               ppi->ppi_offset);
+               vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK;
+               vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >>
+                               VLAN_PRIO_SHIFT;
+       }
+
+       net_trans_info = get_net_transport_info(skb, &hdr_offset);
+       if (net_trans_info == TRANSPORT_INFO_NOT_IP)
+               goto do_send;
+
+       /*
+        * Setup the sendside checksum offload only if this is not a
+        * GSO packet.
+        */
+       if (skb_is_gso(skb))
+               goto do_lso;
 
-       /* Start filling in the page buffers starting after RNDIS buffer. */
-       packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
-       packet->page_buf[1].offset
-               = (unsigned long)skb->data & (PAGE_SIZE - 1);
-       if (npg_data == 1)
-               packet->page_buf[1].len = skb_headlen(skb);
+       rndis_msg_size += NDIS_CSUM_PPI_SIZE;
+       ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
+                           TCPIP_CHKSUM_PKTINFO);
+
+       csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
+                       ppi->ppi_offset);
+
+       if (net_trans_info & (INFO_IPV4 << 16))
+               csum_info->transmit.is_ipv4 = 1;
        else
-               packet->page_buf[1].len = PAGE_SIZE
-                       - packet->page_buf[1].offset;
-
-       for (i = 2; i <= npg_data; i++) {
-               packet->page_buf[i].pfn = virt_to_phys(skb->data
-                       + PAGE_SIZE * (i-1)) >> PAGE_SHIFT;
-               packet->page_buf[i].offset = 0;
-               packet->page_buf[i].len = PAGE_SIZE;
+               csum_info->transmit.is_ipv6 = 1;
+
+       if (net_trans_info & INFO_TCP) {
+               csum_info->transmit.tcp_checksum = 1;
+               csum_info->transmit.tcp_header_offset = hdr_offset;
+       } else if (net_trans_info & INFO_UDP) {
+               csum_info->transmit.udp_checksum = 1;
        }
-       if (npg_data > 1)
-               packet->page_buf[npg_data].len = (((unsigned long)skb->data
-                       + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1;
-
-       /* Additional fragments are after SKB data */
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-               const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
-
-               packet->page_buf[i+npg_data+1].pfn =
-                       page_to_pfn(skb_frag_page(f));
-               packet->page_buf[i+npg_data+1].offset = f->page_offset;
-               packet->page_buf[i+npg_data+1].len = skb_frag_size(f);
+       goto do_send;
+
+do_lso:
+       rndis_msg_size += NDIS_LSO_PPI_SIZE;
+       ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
+                           TCP_LARGESEND_PKTINFO);
+
+       lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
+                       ppi->ppi_offset);
+
+       lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
+       if (net_trans_info & (INFO_IPV4 << 16)) {
+               lso_info->lso_v2_transmit.ip_version =
+                       NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
+               ip_hdr(skb)->tot_len = 0;
+               ip_hdr(skb)->check = 0;
+               tcp_hdr(skb)->check =
+               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+                                  ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
+       } else {
+               lso_info->lso_v2_transmit.ip_version =
+                       NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
+               ipv6_hdr(skb)->payload_len = 0;
+               tcp_hdr(skb)->check =
+               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                               &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
        }
+       lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
+       lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
 
-       /* Set the completion routine */
-       packet->completion.send.send_completion = netvsc_xmit_completion;
-       packet->completion.send.send_completion_ctx = packet;
-       packet->completion.send.send_completion_tid = (unsigned long)skb;
+do_send:
+       /* Start filling in the page buffers with the rndis hdr */
+       rndis_msg->msg_len += rndis_msg_size;
+       packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
+                                       skb, &packet->page_buf[0]);
+
+       ret = netvsc_send(net_device_ctx->device_ctx, packet);
 
-       ret = rndis_filter_send(net_device_ctx->device_ctx,
-                                 packet);
        if (ret == 0) {
                net->stats.tx_bytes += skb->len;
                net->stats.tx_packets++;
@@ -264,7 +485,8 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
  * "wire" on the specified device.
  */
 int netvsc_recv_callback(struct hv_device *device_obj,
-                               struct hv_netvsc_packet *packet)
+                               struct hv_netvsc_packet *packet,
+                               struct ndis_tcp_ip_checksum_info *csum_info)
 {
        struct net_device *net;
        struct sk_buff *skb;
@@ -291,7 +513,17 @@ int netvsc_recv_callback(struct hv_device *device_obj,
                packet->total_data_buflen);
 
        skb->protocol = eth_type_trans(skb, net);
-       skb->ip_summed = CHECKSUM_NONE;
+       if (csum_info) {
+               /* We only look at the IP checksum here.
+                * Should we be dropping the packet if checksum
+                * failed? How do we deal with other checksums - TCP/UDP?
+                */
+               if (csum_info->receive.ip_checksum_succeeded)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               else
+                       skb->ip_summed = CHECKSUM_NONE;
+       }
+
        if (packet->vlan_tci & VLAN_TAG_PRESENT)
                __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
                                       packet->vlan_tci);
@@ -442,6 +674,8 @@ static int netvsc_probe(struct hv_device *dev,
        if (!net)
                return -ENOMEM;
 
+       netif_carrier_off(net);
+
        net_device_ctx = netdev_priv(net);
        net_device_ctx->device_ctx = dev;
        hv_set_drvdata(dev, net);
@@ -450,9 +684,10 @@ static int netvsc_probe(struct hv_device *dev,
 
        net->netdev_ops = &device_ops;
 
-       /* TODO: Add GSO and Checksum offload */
-       net->hw_features = 0;
-       net->features = NETIF_F_HW_VLAN_CTAG_TX;
+       net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM |
+                               NETIF_F_TSO;
+       net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM |
+                       NETIF_F_IP_CSUM | NETIF_F_TSO;
 
        SET_ETHTOOL_OPS(net, &ethtool_ops);
        SET_NETDEV_DEV(net, &dev->device);
@@ -473,6 +708,8 @@ static int netvsc_probe(struct hv_device *dev,
                pr_err("Unable to register netdev.\n");
                rndis_filter_device_remove(dev);
                free_netdev(net);
+       } else {
+               schedule_delayed_work(&net_device_ctx->dwork, 0);
        }
 
        return ret;
index f0cc8ef21e1c246a53d529d1782087ca1045ae7d..4a37e3db9e32f06c1c820c66cb08d79920bf02c0 100644 (file)
@@ -240,6 +240,22 @@ static int rndis_filter_send_request(struct rndis_device *dev,
        return ret;
 }
 
+static void rndis_set_link_state(struct rndis_device *rdev,
+                                struct rndis_request *request)
+{
+       u32 link_status;
+       struct rndis_query_complete *query_complete;
+
+       query_complete = &request->response_msg.msg.query_complete;
+
+       if (query_complete->status == RNDIS_STATUS_SUCCESS &&
+           query_complete->info_buflen == sizeof(u32)) {
+               memcpy(&link_status, (void *)((unsigned long)query_complete +
+                      query_complete->info_buf_offset), sizeof(u32));
+               rdev->link_state = link_status != 0;
+       }
+}
+
 static void rndis_filter_receive_response(struct rndis_device *dev,
                                       struct rndis_message *resp)
 {
@@ -269,6 +285,10 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
                    sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
                        memcpy(&request->response_msg, resp,
                               resp->msg_len);
+                       if (request->request_msg.ndis_msg_type ==
+                           RNDIS_MSG_QUERY && request->request_msg.msg.
+                           query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS)
+                               rndis_set_link_state(dev, request);
                } else {
                        netdev_err(ndev,
                                "rndis response buffer overflow "
@@ -350,6 +370,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
        struct rndis_packet *rndis_pkt;
        u32 data_offset;
        struct ndis_pkt_8021q_info *vlan;
+       struct ndis_tcp_ip_checksum_info *csum_info;
 
        rndis_pkt = &msg->msg.pkt;
 
@@ -388,7 +409,8 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
                pkt->vlan_tci = 0;
        }
 
-       netvsc_recv_callback(dev->net_dev->dev, pkt);
+       csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
+       netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info);
 }
 
 int rndis_filter_receive(struct hv_device *dev,
@@ -607,6 +629,61 @@ cleanup:
        return ret;
 }
 
+int rndis_filter_set_offload_params(struct hv_device *hdev,
+                               struct ndis_offload_params *req_offloads)
+{
+       struct netvsc_device *nvdev = hv_get_drvdata(hdev);
+       struct rndis_device *rdev = nvdev->extension;
+       struct net_device *ndev = nvdev->ndev;
+       struct rndis_request *request;
+       struct rndis_set_request *set;
+       struct ndis_offload_params *offload_params;
+       struct rndis_set_complete *set_complete;
+       u32 extlen = sizeof(struct ndis_offload_params);
+       int ret, t;
+
+       request = get_rndis_request(rdev, RNDIS_MSG_SET,
+               RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
+       if (!request)
+               return -ENOMEM;
+
+       set = &request->request_msg.msg.set_req;
+       set->oid = OID_TCP_OFFLOAD_PARAMETERS;
+       set->info_buflen = extlen;
+       set->info_buf_offset = sizeof(struct rndis_set_request);
+       set->dev_vc_handle = 0;
+
+       offload_params = (struct ndis_offload_params *)((ulong)set +
+                               set->info_buf_offset);
+       *offload_params = *req_offloads;
+       offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT;
+       offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3;
+       offload_params->header.size = extlen;
+
+       ret = rndis_filter_send_request(rdev, request);
+       if (ret != 0)
+               goto cleanup;
+
+       t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+       if (t == 0) {
+               netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n");
+               /* can't put_rndis_request, since we may still receive a
+                * send-completion.
+                */
+               return -EBUSY;
+       } else {
+               set_complete = &request->response_msg.msg.set_complete;
+               if (set_complete->status != RNDIS_STATUS_SUCCESS) {
+                       netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
+                                  set_complete->status);
+                       ret = -EINVAL;
+               }
+       }
+
+cleanup:
+       put_rndis_request(rdev, request);
+       return ret;
+}
 
 static int rndis_filter_query_device_link_status(struct rndis_device *dev)
 {
@@ -617,7 +694,6 @@ static int rndis_filter_query_device_link_status(struct rndis_device *dev)
        ret = rndis_filter_query_device(dev,
                                      RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
                                      &link_status, &size);
-       dev->link_state = (link_status != 0) ? true : false;
 
        return ret;
 }
@@ -807,6 +883,7 @@ int rndis_filter_device_add(struct hv_device *dev,
        struct netvsc_device *net_device;
        struct rndis_device *rndis_device;
        struct netvsc_device_info *device_info = additional_info;
+       struct ndis_offload_params offloads;
 
        rndis_device = get_rndis_device();
        if (!rndis_device)
@@ -846,6 +923,26 @@ int rndis_filter_device_add(struct hv_device *dev,
 
        memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
 
+       /* Turn on the offloads; the host supports all of the relevant
+        * offloads.
+        */
+       memset(&offloads, 0, sizeof(struct ndis_offload_params));
+       /* A value of zero means "no change"; now turn on what we
+        * want.
+        */
+       offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
+
+
+       ret = rndis_filter_set_offload_params(dev, &offloads);
+       if (ret)
+               goto err_dev_remv;
+
+
        rndis_filter_query_device_link_status(rndis_device);
 
        device_info->link_state = rndis_device->link_state;
@@ -855,6 +952,10 @@ int rndis_filter_device_add(struct hv_device *dev,
                 device_info->link_state ? "down" : "up");
 
        return ret;
+
+err_dev_remv:
+       rndis_filter_device_remove(dev);
+       return ret;
 }
 
 void rndis_filter_device_remove(struct hv_device *dev)
@@ -891,69 +992,3 @@ int rndis_filter_close(struct hv_device *dev)
 
        return rndis_filter_close_device(nvdev->extension);
 }
-
-int rndis_filter_send(struct hv_device *dev,
-                            struct hv_netvsc_packet *pkt)
-{
-       struct rndis_message *rndis_msg;
-       struct rndis_packet *rndis_pkt;
-       u32 rndis_msg_size;
-       bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT;
-
-       /* Add the rndis header */
-       rndis_msg = (struct rndis_message *)pkt->extension;
-
-       rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
-       if (isvlan)
-               rndis_msg_size += NDIS_VLAN_PPI_SIZE;
-
-       rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
-       rndis_msg->msg_len = pkt->total_data_buflen +
-                                     rndis_msg_size;
-
-       rndis_pkt = &rndis_msg->msg.pkt;
-       rndis_pkt->data_offset = sizeof(struct rndis_packet);
-       if (isvlan)
-               rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE;
-       rndis_pkt->data_len = pkt->total_data_buflen;
-
-       if (isvlan) {
-               struct rndis_per_packet_info *ppi;
-               struct ndis_pkt_8021q_info *vlan;
-
-               rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
-               rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE;
-
-               ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt +
-                       rndis_pkt->per_pkt_info_offset);
-               ppi->size = NDIS_VLAN_PPI_SIZE;
-               ppi->type = IEEE_8021Q_INFO;
-               ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
-
-               vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi +
-                       ppi->ppi_offset);
-               vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK;
-               vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
-       }
-
-       pkt->is_data_pkt = true;
-       pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT;
-       pkt->page_buf[0].offset =
-                       (unsigned long)rndis_msg & (PAGE_SIZE-1);
-       pkt->page_buf[0].len = rndis_msg_size;
-
-       /* Add one page_buf if the rndis msg goes beyond page boundary */
-       if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) {
-               int i;
-               for (i = pkt->page_buf_cnt; i > 1; i--)
-                       pkt->page_buf[i] = pkt->page_buf[i-1];
-               pkt->page_buf_cnt++;
-               pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset;
-               pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong)
-                       rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT;
-               pkt->page_buf[1].offset = 0;
-               pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len;
-       }
-
-       return netvsc_send(dev, pkt);
-}
index 08ae4655423a6b8f7deeee92d588fa38f0ec5cf4..3e89beab64fdc87559a2b1b9e27a7e6c6ba2b04c 100644 (file)
@@ -15,9 +15,9 @@ config IEEE802154_FAKEHARD
        depends on  IEEE802154_DRIVERS
        ---help---
          Say Y here to enable the fake driver that serves as an example
-          of HardMAC device driver.
+         of HardMAC device driver.
 
-          This driver can also be built as a module. To do so say M here.
+         This driver can also be built as a module. To do so say M here.
          The module will be called 'fakehard'.
 
 config IEEE802154_FAKELB
@@ -31,17 +31,23 @@ config IEEE802154_FAKELB
          The module will be called 'fakelb'.
 
 config IEEE802154_AT86RF230
-        depends on IEEE802154_DRIVERS && MAC802154
-        tristate "AT86RF230/231 transceiver driver"
-        depends on SPI
+       depends on IEEE802154_DRIVERS && MAC802154
+       tristate "AT86RF230/231/233/212 transceiver driver"
+       depends on SPI
+       ---help---
+         Say Y here to enable the at86rf230/231/233/212 SPI 802.15.4 wireless
+         controller.
+
+         This driver can also be built as a module. To do so, say M here.
+         the module will be called 'at86rf230'.
 
 config IEEE802154_MRF24J40
-       tristate "Microchip MRF24J40 transceiver driver"
-       depends on IEEE802154_DRIVERS && MAC802154
-       depends on SPI
-       ---help---
-         Say Y here to enable the MRF24J20 SPI 802.15.4 wireless
-         controller.
-
-         This driver can also be built as a module. To do so, say M here.
-         the module will be called 'mrf24j40'.
+       tristate "Microchip MRF24J40 transceiver driver"
+       depends on IEEE802154_DRIVERS && MAC802154
+       depends on SPI
+       ---help---
+         Say Y here to enable the MRF24J20 SPI 802.15.4 wireless
+         controller.
+
+         This driver can also be built as a module. To do so, say M here.
+         the module will be called 'mrf24j40'.
index 03e24c560b2e0f38db61fdb529078a293bfdd598..e8004ef73bc1c6a900f57b741d1780391cad769f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/at86rf230.h>
 #include <linux/skbuff.h>
+#include <linux/of_gpio.h>
 
 #include <net/mac802154.h>
 #include <net/wpan-phy.h>
@@ -244,6 +245,7 @@ static bool is_rf212(struct at86rf230_local *local)
 #define STATE_TX_ON            0x09
 /* 0x0a - 0x0e */                      /* 0x0a - UNSUPPORTED_ATTRIBUTE */
 #define STATE_SLEEP            0x0F
+#define STATE_PREP_DEEP_SLEEP  0x10
 #define STATE_BUSY_RX_AACK     0x11
 #define STATE_BUSY_TX_ARET     0x12
 #define STATE_RX_AACK_ON       0x16
@@ -573,7 +575,7 @@ at86rf230_start(struct ieee802154_dev *dev)
        if (rc)
                return rc;
 
-       rc = at86rf230_state(dev, STATE_FORCE_TX_ON);
+       rc = at86rf230_state(dev, STATE_TX_ON);
        if (rc)
                return rc;
 
@@ -654,12 +656,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
        int rc;
        unsigned long flags;
 
-       spin_lock(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        if  (lp->irq_busy) {
-               spin_unlock(&lp->lock);
+               spin_unlock_irqrestore(&lp->lock, flags);
                return -EBUSY;
        }
-       spin_unlock(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
 
        might_sleep();
 
@@ -744,30 +746,31 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
        struct at86rf230_local *lp = dev->priv;
 
        if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+               u16 addr = le16_to_cpu(filt->short_addr);
+
                dev_vdbg(&lp->spi->dev,
                        "at86rf230_set_hw_addr_filt called for saddr\n");
-               __at86rf230_write(lp, RG_SHORT_ADDR_0, filt->short_addr);
-               __at86rf230_write(lp, RG_SHORT_ADDR_1, filt->short_addr >> 8);
+               __at86rf230_write(lp, RG_SHORT_ADDR_0, addr);
+               __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
        }
 
        if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+               u16 pan = le16_to_cpu(filt->pan_id);
+
                dev_vdbg(&lp->spi->dev,
                        "at86rf230_set_hw_addr_filt called for pan id\n");
-               __at86rf230_write(lp, RG_PAN_ID_0, filt->pan_id);
-               __at86rf230_write(lp, RG_PAN_ID_1, filt->pan_id >> 8);
+               __at86rf230_write(lp, RG_PAN_ID_0, pan);
+               __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
        }
 
        if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+               u8 i, addr[8];
+
+               memcpy(addr, &filt->ieee_addr, 8);
                dev_vdbg(&lp->spi->dev,
                        "at86rf230_set_hw_addr_filt called for IEEE addr\n");
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_0, filt->ieee_addr[7]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_1, filt->ieee_addr[6]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_2, filt->ieee_addr[5]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_3, filt->ieee_addr[4]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_4, filt->ieee_addr[3]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_5, filt->ieee_addr[2]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_6, filt->ieee_addr[1]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_7, filt->ieee_addr[0]);
+               for (i = 0; i < 8; i++)
+                       __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
        }
 
        if (changed & IEEE802515_AFILT_PANC_CHANGED) {
@@ -912,8 +915,8 @@ static void at86rf230_irqwork(struct work_struct *work)
        status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/
 
        if (status & IRQ_TRX_END) {
-               spin_lock_irqsave(&lp->lock, flags);
                status &= ~IRQ_TRX_END;
+               spin_lock_irqsave(&lp->lock, flags);
                if (lp->is_tx) {
                        lp->is_tx = 0;
                        spin_unlock_irqrestore(&lp->lock, flags);
@@ -942,10 +945,11 @@ static void at86rf230_irqwork_level(struct work_struct *work)
 static irqreturn_t at86rf230_isr(int irq, void *data)
 {
        struct at86rf230_local *lp = data;
+       unsigned long flags;
 
-       spin_lock(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        lp->irq_busy = 1;
-       spin_unlock(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
 
        schedule_work(&lp->irqwork);
 
@@ -1032,6 +1036,40 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
        return 0;
 }
 
+static struct at86rf230_platform_data *
+at86rf230_get_pdata(struct spi_device *spi)
+{
+       struct at86rf230_platform_data *pdata;
+       const char *irq_type;
+
+       if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node)
+               return spi->dev.platform_data;
+
+       pdata = devm_kzalloc(&spi->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               goto done;
+
+       pdata->rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
+       pdata->slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0);
+
+       pdata->irq_type = IRQF_TRIGGER_RISING;
+       of_property_read_string(spi->dev.of_node, "irq-type", &irq_type);
+       if (!strcmp(irq_type, "level-high"))
+               pdata->irq_type = IRQF_TRIGGER_HIGH;
+       else if (!strcmp(irq_type, "level-low"))
+               pdata->irq_type = IRQF_TRIGGER_LOW;
+       else if (!strcmp(irq_type, "edge-rising"))
+               pdata->irq_type = IRQF_TRIGGER_RISING;
+       else if (!strcmp(irq_type, "edge-falling"))
+               pdata->irq_type = IRQF_TRIGGER_FALLING;
+       else
+               dev_warn(&spi->dev, "wrong irq-type specified using edge-rising\n");
+
+       spi->dev.platform_data = pdata;
+done:
+       return pdata;
+}
+
 static int at86rf230_probe(struct spi_device *spi)
 {
        struct at86rf230_platform_data *pdata;
@@ -1050,15 +1088,17 @@ static int at86rf230_probe(struct spi_device *spi)
                return -EINVAL;
        }
 
-       pdata = spi->dev.platform_data;
+       pdata = at86rf230_get_pdata(spi);
        if (!pdata) {
                dev_err(&spi->dev, "no platform_data\n");
                return -EINVAL;
        }
 
-       rc = gpio_request(pdata->rstn, "rstn");
-       if (rc)
-               return rc;
+       if (gpio_is_valid(pdata->rstn)) {
+               rc = gpio_request(pdata->rstn, "rstn");
+               if (rc)
+                       return rc;
+       }
 
        if (gpio_is_valid(pdata->slp_tr)) {
                rc = gpio_request(pdata->slp_tr, "slp_tr");
@@ -1066,9 +1106,11 @@ static int at86rf230_probe(struct spi_device *spi)
                        goto err_slp_tr;
        }
 
-       rc = gpio_direction_output(pdata->rstn, 1);
-       if (rc)
-               goto err_gpio_dir;
+       if (gpio_is_valid(pdata->rstn)) {
+               rc = gpio_direction_output(pdata->rstn, 1);
+               if (rc)
+                       goto err_gpio_dir;
+       }
 
        if (gpio_is_valid(pdata->slp_tr)) {
                rc = gpio_direction_output(pdata->slp_tr, 0);
@@ -1077,11 +1119,13 @@ static int at86rf230_probe(struct spi_device *spi)
        }
 
        /* Reset */
-       msleep(1);
-       gpio_set_value(pdata->rstn, 0);
-       msleep(1);
-       gpio_set_value(pdata->rstn, 1);
-       msleep(1);
+       if (gpio_is_valid(pdata->rstn)) {
+               udelay(1);
+               gpio_set_value(pdata->rstn, 0);
+               udelay(1);
+               gpio_set_value(pdata->rstn, 1);
+               usleep_range(120, 240);
+       }
 
        rc = __at86rf230_detect_device(spi, &man_id, &part, &version);
        if (rc < 0)
@@ -1108,6 +1152,10 @@ static int at86rf230_probe(struct spi_device *spi)
                if (version == 1)
                        ops = &at86rf212_ops;
                break;
+       case 11:
+               chip = "at86rf233";
+               ops = &at86rf230_ops;
+               break;
        default:
                chip = "UNKNOWN";
                break;
@@ -1191,7 +1239,8 @@ err_gpio_dir:
        if (gpio_is_valid(pdata->slp_tr))
                gpio_free(pdata->slp_tr);
 err_slp_tr:
-       gpio_free(pdata->rstn);
+       if (gpio_is_valid(pdata->rstn))
+               gpio_free(pdata->rstn);
        return rc;
 }
 
@@ -1207,7 +1256,8 @@ static int at86rf230_remove(struct spi_device *spi)
 
        if (gpio_is_valid(pdata->slp_tr))
                gpio_free(pdata->slp_tr);
-       gpio_free(pdata->rstn);
+       if (gpio_is_valid(pdata->rstn))
+               gpio_free(pdata->rstn);
 
        mutex_destroy(&lp->bmux);
        ieee802154_free_device(lp->dev);
@@ -1216,8 +1266,19 @@ static int at86rf230_remove(struct spi_device *spi)
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_OF)
+static struct of_device_id at86rf230_of_match[] = {
+       { .compatible = "atmel,at86rf230", },
+       { .compatible = "atmel,at86rf231", },
+       { .compatible = "atmel,at86rf233", },
+       { .compatible = "atmel,at86rf212", },
+       { },
+};
+#endif
+
 static struct spi_driver at86rf230_driver = {
        .driver = {
+               .of_match_table = of_match_ptr(at86rf230_of_match),
                .name   = "at86rf230",
                .owner  = THIS_MODULE,
        },
index bf0d55e2dd635613c3712b5b73ab528217e5cff7..78f18be3bbf2a76b7c245abef4aabd34faf3c72f 100644 (file)
@@ -63,11 +63,11 @@ static struct wpan_phy *fake_get_phy(const struct net_device *dev)
  *
  * Return the ID of the PAN from the PIB.
  */
-static u16 fake_get_pan_id(const struct net_device *dev)
+static __le16 fake_get_pan_id(const struct net_device *dev)
 {
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       return 0xeba1;
+       return cpu_to_le16(0xeba1);
 }
 
 /**
@@ -78,11 +78,11 @@ static u16 fake_get_pan_id(const struct net_device *dev)
  * device. If the device has not yet had a short address assigned
  * then this should return 0xFFFF to indicate a lack of association.
  */
-static u16 fake_get_short_addr(const struct net_device *dev)
+static __le16 fake_get_short_addr(const struct net_device *dev)
 {
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       return 0x1;
+       return cpu_to_le16(0x1);
 }
 
 /**
@@ -149,7 +149,7 @@ static int fake_assoc_req(struct net_device *dev,
  *       802.15.4-2006 document.
  */
 static int fake_assoc_resp(struct net_device *dev,
-               struct ieee802154_addr *addr, u16 short_addr, u8 status)
+               struct ieee802154_addr *addr, __le16 short_addr, u8 status)
 {
        return 0;
 }
@@ -191,10 +191,10 @@ static int fake_disassoc_req(struct net_device *dev,
  * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
  * document, with 7.3.8 describing coordinator realignment.
  */
-static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
-                               u8 channel, u8 page,
-                               u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
-                               u8 coord_realign)
+static int fake_start_req(struct net_device *dev,
+                         struct ieee802154_addr *addr, u8 channel, u8 page,
+                         u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+                         u8 coord_realign)
 {
        struct wpan_phy *phy = fake_to_phy(dev);
 
@@ -281,8 +281,8 @@ static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
        switch (cmd) {
        case SIOCGIFADDR:
                /* FIXME: fixed here, get from device IRL */
-               pan_id = fake_get_pan_id(dev);
-               short_addr = fake_get_short_addr(dev);
+               pan_id = le16_to_cpu(fake_get_pan_id(dev));
+               short_addr = le16_to_cpu(fake_get_short_addr(dev));
                if (pan_id == IEEE802154_PANID_BROADCAST ||
                    short_addr == IEEE802154_ADDR_BROADCAST)
                        return -EADDRNOTAVAIL;
index 246befa4ba0571383f13cbdef2a701156b0326d0..78a6552ed7072d04672b98d7731c0ffd4af6117b 100644 (file)
@@ -465,8 +465,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
        if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
                /* Short Addr */
                u8 addrh, addrl;
-               addrh = filt->short_addr >> 8 & 0xff;
-               addrl = filt->short_addr & 0xff;
+               addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff;
+               addrl = le16_to_cpu(filt->short_addr) & 0xff;
 
                write_short_reg(devrec, REG_SADRH, addrh);
                write_short_reg(devrec, REG_SADRL, addrl);
@@ -476,15 +476,16 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
 
        if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
                /* Device Address */
-               int i;
+               u8 i, addr[8];
+
+               memcpy(addr, &filt->ieee_addr, 8);
                for (i = 0; i < 8; i++)
-                       write_short_reg(devrec, REG_EADR0+i,
-                                       filt->ieee_addr[7-i]);
+                       write_short_reg(devrec, REG_EADR0 + i, addr[i]);
 
 #ifdef DEBUG
                printk(KERN_DEBUG "Set long addr to: ");
                for (i = 0; i < 8; i++)
-                       printk("%02hhx ", filt->ieee_addr[i]);
+                       printk("%02hhx ", addr[7 - i]);
                printk(KERN_DEBUG "\n");
 #endif
        }
@@ -492,8 +493,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
        if (changed & IEEE802515_AFILT_PANID_CHANGED) {
                /* PAN ID */
                u8 panidl, panidh;
-               panidh = filt->pan_id >> 8 & 0xff;
-               panidl = filt->pan_id & 0xff;
+               panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff;
+               panidl = le16_to_cpu(filt->pan_id) & 0xff;
                write_short_reg(devrec, REG_PANIDH, panidh);
                write_short_reg(devrec, REG_PANIDL, panidl);
 
index c14d39bf32d06a6f8d1b42a29b36dcd84b25c8f6..1da36764b1a431f6fc05cccca50a051c08a418f9 100644 (file)
@@ -136,18 +136,18 @@ static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev,
        unsigned int start;
 
        do {
-               start = u64_stats_fetch_begin_bh(&dp->rsync);
+               start = u64_stats_fetch_begin_irq(&dp->rsync);
                stats->rx_packets = dp->rx_packets;
                stats->rx_bytes = dp->rx_bytes;
-       } while (u64_stats_fetch_retry_bh(&dp->rsync, start));
+       } while (u64_stats_fetch_retry_irq(&dp->rsync, start));
 
        do {
-               start = u64_stats_fetch_begin_bh(&dp->tsync);
+               start = u64_stats_fetch_begin_irq(&dp->tsync);
 
                stats->tx_packets = dp->tx_packets;
                stats->tx_bytes = dp->tx_bytes;
 
-       } while (u64_stats_fetch_retry_bh(&dp->tsync, start));
+       } while (u64_stats_fetch_retry_irq(&dp->tsync, start));
 
        stats->rx_dropped = dev->stats.rx_dropped;
        stats->tx_dropped = dev->stats.tx_dropped;
index 282effee7e1c22072c390fcbe503873fd3497fbd..bb96409f8c056b85b77255f1c397edb4b28b0511 100644 (file)
@@ -111,10 +111,10 @@ static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
 
                lb_stats = per_cpu_ptr(dev->lstats, i);
                do {
-                       start = u64_stats_fetch_begin_bh(&lb_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&lb_stats->syncp);
                        tbytes = lb_stats->bytes;
                        tpackets = lb_stats->packets;
-               } while (u64_stats_fetch_retry_bh(&lb_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start));
                bytes   += tbytes;
                packets += tpackets;
        }
index 44227c25a276a71068e737d84b61939d0dd0253c..753a8c23d15d9af1e138ec6fda410aeda32d288b 100644 (file)
@@ -506,6 +506,9 @@ static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
 static struct lock_class_key macvlan_netdev_xmit_lock_key;
 static struct lock_class_key macvlan_netdev_addr_lock_key;
 
+#define ALWAYS_ON_FEATURES \
+       (NETIF_F_SG | NETIF_F_GEN_CSUM | NETIF_F_GSO_SOFTWARE | NETIF_F_LLTX)
+
 #define MACVLAN_FEATURES \
        (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
         NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
@@ -538,7 +541,7 @@ static int macvlan_init(struct net_device *dev)
        dev->state              = (dev->state & ~MACVLAN_STATE_MASK) |
                                  (lowerdev->state & MACVLAN_STATE_MASK);
        dev->features           = lowerdev->features & MACVLAN_FEATURES;
-       dev->features           |= NETIF_F_LLTX;
+       dev->features           |= ALWAYS_ON_FEATURES;
        dev->gso_max_size       = lowerdev->gso_max_size;
        dev->iflink             = lowerdev->ifindex;
        dev->hard_header_len    = lowerdev->hard_header_len;
@@ -579,13 +582,13 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
                for_each_possible_cpu(i) {
                        p = per_cpu_ptr(vlan->pcpu_stats, i);
                        do {
-                               start = u64_stats_fetch_begin_bh(&p->syncp);
+                               start = u64_stats_fetch_begin_irq(&p->syncp);
                                rx_packets      = p->rx_packets;
                                rx_bytes        = p->rx_bytes;
                                rx_multicast    = p->rx_multicast;
                                tx_packets      = p->tx_packets;
                                tx_bytes        = p->tx_bytes;
-                       } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                        stats->rx_packets       += rx_packets;
                        stats->rx_bytes         += rx_bytes;
@@ -692,7 +695,7 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev,
        features = netdev_increment_features(vlan->lowerdev->features,
                                             features,
                                             mask);
-       features |= NETIF_F_LLTX;
+       features |= ALWAYS_ON_FEATURES;
 
        return features;
 }
index 14ce7de6a933aee0539e7b2e332635b03cb18b7c..6929b03ec638b04e561d168347cf2ba5bef241d6 100644 (file)
@@ -90,10 +90,10 @@ nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
                nl_stats = per_cpu_ptr(dev->lstats, i);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&nl_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&nl_stats->syncp);
                        tbytes = nl_stats->bytes;
                        tpackets = nl_stats->packets;
-               } while (u64_stats_fetch_retry_bh(&nl_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&nl_stats->syncp, start));
 
                packets += tpackets;
                bytes += tbytes;
index 643b5d665f418d45d39e55e246ce33dd875158cc..1d788f19135bdf5e59e71a11eed935981a172ca8 100644 (file)
@@ -186,9 +186,9 @@ static const struct phy_setting settings[] = {
  *   of that setting.  Returns the index of the last setting if
  *   none of the others match.
  */
-static inline int phy_find_setting(int speed, int duplex)
+static inline unsigned int phy_find_setting(int speed, int duplex)
 {
-       int idx = 0;
+       unsigned int idx = 0;
 
        while (idx < ARRAY_SIZE(settings) &&
               (settings[idx].speed != speed || settings[idx].duplex != duplex))
@@ -207,7 +207,7 @@ static inline int phy_find_setting(int speed, int duplex)
  *   the mask in features.  Returns the index of the last setting
  *   if nothing else matches.
  */
-static inline int phy_find_valid(int idx, u32 features)
+static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
 {
        while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
                idx++;
@@ -226,7 +226,7 @@ static inline int phy_find_valid(int idx, u32 features)
 static void phy_sanitize_settings(struct phy_device *phydev)
 {
        u32 features = phydev->supported;
-       int idx;
+       unsigned int idx;
 
        /* Sanitize settings based on PHY capabilities */
        if ((features & SUPPORTED_Autoneg) == 0)
@@ -979,7 +979,8 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
            (phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
                int eee_lp, eee_cap, eee_adv;
                u32 lp, cap, adv;
-               int idx, status;
+               int status;
+               unsigned int idx;
 
                /* Read phy status to properly get the right settings */
                status = phy_read_status(phydev);
index a70b604ac6446bc2347e48f821002517f62afca1..a2fbb3e1db9a2779b33f6d5d0bda505e549249a1 100644 (file)
@@ -933,6 +933,8 @@ int genphy_read_status(struct phy_device *phydev)
        int err;
        int lpa;
        int lpagb = 0;
+       int common_adv;
+       int common_adv_gb = 0;
 
        /* Update the link, but return if there was an error */
        err = genphy_update_link(phydev);
@@ -954,7 +956,7 @@ int genphy_read_status(struct phy_device *phydev)
 
                        phydev->lp_advertising =
                                mii_stat1000_to_ethtool_lpa_t(lpagb);
-                       lpagb &= adv << 2;
+                       common_adv_gb = lpagb & adv << 2;
                }
 
                lpa = phy_read(phydev, MII_LPA);
@@ -967,25 +969,25 @@ int genphy_read_status(struct phy_device *phydev)
                if (adv < 0)
                        return adv;
 
-               lpa &= adv;
+               common_adv = lpa & adv;
 
                phydev->speed = SPEED_10;
                phydev->duplex = DUPLEX_HALF;
                phydev->pause = 0;
                phydev->asym_pause = 0;
 
-               if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+               if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) {
                        phydev->speed = SPEED_1000;
 
-                       if (lpagb & LPA_1000FULL)
+                       if (common_adv_gb & LPA_1000FULL)
                                phydev->duplex = DUPLEX_FULL;
-               } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+               } else if (common_adv & (LPA_100FULL | LPA_100HALF)) {
                        phydev->speed = SPEED_100;
 
-                       if (lpa & LPA_100FULL)
+                       if (common_adv & LPA_100FULL)
                                phydev->duplex = DUPLEX_FULL;
                } else
-                       if (lpa & LPA_10FULL)
+                       if (common_adv & LPA_10FULL)
                                phydev->duplex = DUPLEX_FULL;
 
                if (phydev->duplex == DUPLEX_FULL) {
index aea92f02401b0eaf25797e95f923481e9a471661..2b1a1d61072c01b474551ed11df96a0e57331427 100644 (file)
@@ -1761,13 +1761,13 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
        for_each_possible_cpu(i) {
                p = per_cpu_ptr(team->pcpu_stats, i);
                do {
-                       start = u64_stats_fetch_begin_bh(&p->syncp);
+                       start = u64_stats_fetch_begin_irq(&p->syncp);
                        rx_packets      = p->rx_packets;
                        rx_bytes        = p->rx_bytes;
                        rx_multicast    = p->rx_multicast;
                        tx_packets      = p->tx_packets;
                        tx_bytes        = p->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                stats->rx_packets       += rx_packets;
                stats->rx_bytes         += rx_bytes;
index d671fc3ac5ac26ad2b7666617fab5adc1042e569..dbde3412ee5eafdeb39cd238e8af4f19368917c6 100644 (file)
@@ -432,9 +432,9 @@ static void __lb_one_cpu_stats_add(struct lb_stats *acc_stats,
        struct lb_stats tmp;
 
        do {
-               start = u64_stats_fetch_begin_bh(syncp);
+               start = u64_stats_fetch_begin_irq(syncp);
                tmp.tx_bytes = cpu_stats->tx_bytes;
-       } while (u64_stats_fetch_retry_bh(syncp, start));
+       } while (u64_stats_fetch_retry_irq(syncp, start));
        acc_stats->tx_bytes += tmp.tx_bytes;
 }
 
index 8fe9cb7d0f72e9fb7d34307f9a12797772844db1..26f8635b027d3fb44ab12223000badc214098df0 100644 (file)
@@ -1686,7 +1686,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                                   TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
                                   NETIF_F_HW_VLAN_STAG_TX;
                dev->features = dev->hw_features;
-               dev->vlan_features = dev->features;
+               dev->vlan_features = dev->features &
+                                    ~(NETIF_F_HW_VLAN_CTAG_TX |
+                                      NETIF_F_HW_VLAN_STAG_TX);
 
                INIT_LIST_HEAD(&tun->disabled);
                err = tun_attach(tun, file, false);
index 433f0a00c68324e46e60aa04b8e16989fac36701..e2797f1e1b31ee51f82c11d50b23e6bd274d29ab 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_USB_HSO)         += hso.o
 obj-$(CONFIG_USB_NET_AX8817X)  += asix.o
 asix-y := asix_devices.o asix_common.o ax88172a.o
 obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
-obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o
+obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)  += cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)   += dm9601.o
 obj-$(CONFIG_USB_NET_SR9700)   += sr9700.o
index 955df81a43589bc30857b56db94f94886ce9cc30..054e59ca6946446389cd22eb1e851a6b4fad6633 100644 (file)
@@ -1029,20 +1029,12 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = 0x03;
        dev->mii.supports_gmii = 1;
 
-       if (usb_device_no_sg_constraint(dev->udev))
-               dev->can_dma_sg = 1;
-
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                              NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                                 NETIF_F_RXCSUM;
 
-       if (dev->can_dma_sg) {
-               dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
-               dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
-       }
-
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
               AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
@@ -1395,6 +1387,19 @@ static const struct driver_info ax88178a_info = {
        .tx_fixup = ax88179_tx_fixup,
 };
 
+static const struct driver_info dlink_dub1312_info = {
+       .description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter",
+       .bind = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset = ax88179_reset,
+       .stop = ax88179_stop,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
 static const struct driver_info sitecom_info = {
        .description = "Sitecom USB 3.0 to Gigabit Adapter",
        .bind = ax88179_bind,
@@ -1421,6 +1426,19 @@ static const struct driver_info samsung_info = {
        .tx_fixup = ax88179_tx_fixup,
 };
 
+static const struct driver_info lenovo_info = {
+       .description = "Lenovo OneLinkDock Gigabit LAN",
+       .bind = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset = ax88179_reset,
+       .stop = ax88179_stop,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
 static const struct usb_device_id products[] = {
 {
        /* ASIX AX88179 10/100/1000 */
@@ -1430,6 +1448,10 @@ static const struct usb_device_id products[] = {
        /* ASIX AX88178A 10/100/1000 */
        USB_DEVICE(0x0b95, 0x178a),
        .driver_info = (unsigned long)&ax88178a_info,
+}, {
+       /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */
+       USB_DEVICE(0x2001, 0x4a00),
+       .driver_info = (unsigned long)&dlink_dub1312_info,
 }, {
        /* Sitecom USB 3.0 to Gigabit Adapter */
        USB_DEVICE(0x0df6, 0x0072),
@@ -1438,6 +1460,10 @@ static const struct usb_device_id products[] = {
        /* Samsung USB Ethernet Adapter */
        USB_DEVICE(0x04e8, 0xa100),
        .driver_info = (unsigned long)&samsung_info,
+}, {
+       /* Lenovo OneLinkDock Gigabit LAN */
+       USB_DEVICE(0x17ef, 0x304b),
+       .driver_info = (unsigned long)&lenovo_info,
 },
        { },
 };
index 42e176912c8ea151606883c0b8563e45fa95a447..bd363b27e8540e3bfe2acc6173adcc8a1952f4b7 100644 (file)
@@ -652,6 +652,13 @@ static const struct usb_device_id  products[] = {
        .driver_info = 0,
 },
 
+/* 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,
+},
+
 /* WHITELIST!!!
  *
  * CDC Ether uses two interfaces, not necessarily consecutive.
index acfcc32b323d87c1b6f4e64788802af932f74319..8f37efd2d2fbb3ec05fcde896b8b9e88136c2f35 100644 (file)
@@ -210,7 +210,7 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                         * (0x86dd) so Linux can understand it.
                         */
                        if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60)
-                               ethhdr->h_proto = __constant_htons(ETH_P_IPV6);
+                               ethhdr->h_proto = htons(ETH_P_IPV6);
                }
 
                if (count) {
index 0654bd3c4591990632463bbafba71c8558dae0a3..18e12a3f7fc302399167bd32712a5ed66fe8fd36 100644 (file)
 #include <linux/list.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v1.05.0 (2014/02/18)"
+#define DRIVER_VERSION "v1.06.0 (2014/03/03)"
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
 #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
 #define MODULENAME "r8152"
@@ -59,7 +60,7 @@
 #define PLA_TCR0               0xe610
 #define PLA_TCR1               0xe612
 #define PLA_TXFIFO_CTRL                0xe618
-#define PLA_RSTTELLY           0xe800
+#define PLA_RSTTALLY           0xe800
 #define PLA_CR                 0xe813
 #define PLA_CRWECR             0xe81c
 #define PLA_CONFIG12           0xe81e  /* CONFIG1, CONFIG2 */
@@ -71,7 +72,7 @@
 #define PLA_MISC_0             0xe858
 #define PLA_MISC_1             0xe85a
 #define PLA_OCP_GPHY_BASE      0xe86c
-#define PLA_TELLYCNT           0xe890
+#define PLA_TALLYCNT           0xe890
 #define PLA_SFF_STS_7          0xe8de
 #define PLA_PHYSTATUS          0xe908
 #define PLA_BP_BA              0xfc26
 /* PLA_TCR1 */
 #define VERSION_MASK           0x7cf0
 
+/* PLA_RSTTALLY */
+#define TALLY_RESET            0x0001
+
 /* PLA_CR */
 #define CR_RST                 0x10
 #define CR_RE                  0x08
@@ -447,6 +451,7 @@ enum rtl8152_flags {
        RTL8152_LINK_CHG,
        SELECTIVE_SUSPEND,
        PHY_RESET,
+       SCHEDULE_TASKLET,
 };
 
 /* Define these values to match your device */
@@ -463,11 +468,37 @@ enum rtl8152_flags {
 #define REALTEK_USB_DEVICE(vend, prod) \
        USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC)
 
+struct tally_counter {
+       __le64  tx_packets;
+       __le64  rx_packets;
+       __le64  tx_errors;
+       __le32  rx_errors;
+       __le16  rx_missed;
+       __le16  align_errors;
+       __le32  tx_one_collision;
+       __le32  tx_multi_collision;
+       __le64  rx_unicast;
+       __le64  rx_broadcast;
+       __le32  rx_multicast;
+       __le16  tx_aborted;
+       __le16  tx_underun;
+};
+
 struct rx_desc {
        __le32 opts1;
 #define RX_LEN_MASK                    0x7fff
+
        __le32 opts2;
+#define RD_UDP_CS                      (1 << 23)
+#define RD_TCP_CS                      (1 << 22)
+#define RD_IPV6_CS                     (1 << 20)
+#define RD_IPV4_CS                     (1 << 19)
+
        __le32 opts3;
+#define IPF                            (1 << 23) /* IP checksum fail */
+#define UDPF                           (1 << 22) /* UDP checksum fail */
+#define TCPF                           (1 << 21) /* TCP checksum fail */
+
        __le32 opts4;
        __le32 opts5;
        __le32 opts6;
@@ -477,13 +508,21 @@ struct tx_desc {
        __le32 opts1;
 #define TX_FS                  (1 << 31) /* First segment of a packet */
 #define TX_LS                  (1 << 30) /* Final segment of a packet */
-#define TX_LEN_MASK            0x3ffff
+#define GTSENDV4               (1 << 28)
+#define GTSENDV6               (1 << 27)
+#define GTTCPHO_SHIFT          18
+#define GTTCPHO_MAX            0x7fU
+#define TX_LEN_MAX             0x3ffffU
 
        __le32 opts2;
 #define UDP_CS                 (1 << 31) /* Calculate UDP/IP checksum */
 #define TCP_CS                 (1 << 30) /* Calculate TCP/IP checksum */
 #define IPV4_CS                        (1 << 29) /* Calculate IPv4 checksum */
 #define IPV6_CS                        (1 << 28) /* Calculate IPv6 checksum */
+#define MSS_SHIFT              17
+#define MSS_MAX                        0x7ffU
+#define TCPHO_SHIFT            17
+#define TCPHO_MAX              0x7ffU
 };
 
 struct r8152;
@@ -550,12 +589,21 @@ enum rtl_version {
        RTL_VER_MAX
 };
 
+enum tx_csum_stat {
+       TX_CSUM_SUCCESS = 0,
+       TX_CSUM_TSO,
+       TX_CSUM_NONE
+};
+
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
  * The RTL chips use a 64 element hash table based on the Ethernet CRC.
  */
 static const int multicast_filter_limit = 32;
 static unsigned int rx_buf_sz = 16384;
 
+#define RTL_LIMITED_TSO_SIZE   (rx_buf_sz - sizeof(struct tx_desc) - \
+                                VLAN_ETH_HLEN - VLAN_HLEN)
+
 static
 int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 {
@@ -593,6 +641,7 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
                               value, index, tmp, size, 500);
 
        kfree(tmp);
+
        return ret;
 }
 
@@ -959,15 +1008,9 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
        return 0;
 }
 
-static struct net_device_stats *rtl8152_get_stats(struct net_device *dev)
-{
-       return &dev->stats;
-}
-
 static void read_bulk_callback(struct urb *urb)
 {
        struct net_device *netdev;
-       unsigned long flags;
        int status = urb->status;
        struct rx_agg *agg;
        struct r8152 *tp;
@@ -1001,9 +1044,9 @@ static void read_bulk_callback(struct urb *urb)
                if (urb->actual_length < ETH_ZLEN)
                        break;
 
-               spin_lock_irqsave(&tp->rx_lock, flags);
+               spin_lock(&tp->rx_lock);
                list_add_tail(&agg->list, &tp->rx_done);
-               spin_unlock_irqrestore(&tp->rx_lock, flags);
+               spin_unlock(&tp->rx_lock);
                tasklet_schedule(&tp->tl);
                return;
        case -ESHUTDOWN:
@@ -1026,9 +1069,9 @@ static void read_bulk_callback(struct urb *urb)
        if (result == -ENODEV) {
                netif_device_detach(tp->netdev);
        } else if (result) {
-               spin_lock_irqsave(&tp->rx_lock, flags);
+               spin_lock(&tp->rx_lock);
                list_add_tail(&agg->list, &tp->rx_done);
-               spin_unlock_irqrestore(&tp->rx_lock, flags);
+               spin_unlock(&tp->rx_lock);
                tasklet_schedule(&tp->tl);
        }
 }
@@ -1036,7 +1079,7 @@ static void read_bulk_callback(struct urb *urb)
 static void write_bulk_callback(struct urb *urb)
 {
        struct net_device_stats *stats;
-       unsigned long flags;
+       struct net_device *netdev;
        struct tx_agg *agg;
        struct r8152 *tp;
        int status = urb->status;
@@ -1049,23 +1092,24 @@ static void write_bulk_callback(struct urb *urb)
        if (!tp)
                return;
 
-       stats = rtl8152_get_stats(tp->netdev);
+       netdev = tp->netdev;
+       stats = &netdev->stats;
        if (status) {
                if (net_ratelimit())
-                       netdev_warn(tp->netdev, "Tx status %d\n", status);
+                       netdev_warn(netdev, "Tx status %d\n", status);
                stats->tx_errors += agg->skb_num;
        } else {
                stats->tx_packets += agg->skb_num;
                stats->tx_bytes += agg->skb_len;
        }
 
-       spin_lock_irqsave(&tp->tx_lock, flags);
+       spin_lock(&tp->tx_lock);
        list_add_tail(&agg->list, &tp->tx_free);
-       spin_unlock_irqrestore(&tp->tx_lock, flags);
+       spin_unlock(&tp->tx_lock);
 
        usb_autopm_put_interface_async(tp->intf);
 
-       if (!netif_carrier_ok(tp->netdev))
+       if (!netif_carrier_ok(netdev))
                return;
 
        if (!test_bit(WORK_ENABLE, &tp->flags))
@@ -1075,7 +1119,7 @@ static void write_bulk_callback(struct urb *urb)
                return;
 
        if (!skb_queue_empty(&tp->tx_queue))
-               schedule_delayed_work(&tp->schedule, 0);
+               tasklet_schedule(&tp->tl);
 }
 
 static void intr_callback(struct urb *urb)
@@ -1270,6 +1314,9 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
        struct tx_agg *agg = NULL;
        unsigned long flags;
 
+       if (list_empty(&tp->tx_free))
+               return NULL;
+
        spin_lock_irqsave(&tp->tx_lock, flags);
        if (!list_empty(&tp->tx_free)) {
                struct list_head *cursor;
@@ -1283,24 +1330,138 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
        return agg;
 }
 
-static void
-r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
+static inline __be16 get_protocol(struct sk_buff *skb)
 {
-       memset(desc, 0, sizeof(*desc));
+       __be16 protocol;
+
+       if (skb->protocol == htons(ETH_P_8021Q))
+               protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+       else
+               protocol = skb->protocol;
 
-       desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS);
+       return protocol;
+}
 
-       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               __be16 protocol;
+/*
+ * r8152_csum_workaround()
+ * The hw limites the value the transport offset. When the offset is out of the
+ * range, calculate the checksum by sw.
+ */
+static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb,
+                                 struct sk_buff_head *list)
+{
+       if (skb_shinfo(skb)->gso_size) {
+               netdev_features_t features = tp->netdev->features;
+               struct sk_buff_head seg_list;
+               struct sk_buff *segs, *nskb;
+
+               features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO);
+               segs = skb_gso_segment(skb, features);
+               if (IS_ERR(segs) || !segs)
+                       goto drop;
+
+               __skb_queue_head_init(&seg_list);
+
+               do {
+                       nskb = segs;
+                       segs = segs->next;
+                       nskb->next = NULL;
+                       __skb_queue_tail(&seg_list, nskb);
+               } while (segs);
+
+               skb_queue_splice(&seg_list, list);
+               dev_kfree_skb(skb);
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               if (skb_checksum_help(skb) < 0)
+                       goto drop;
+
+               __skb_queue_head(list, skb);
+       } else {
+               struct net_device_stats *stats;
+
+drop:
+               stats = &tp->netdev->stats;
+               stats->tx_dropped++;
+               dev_kfree_skb(skb);
+       }
+}
+
+/*
+ * msdn_giant_send_check()
+ * According to the document of microsoft, the TCP Pseudo Header excludes the
+ * packet length for IPv6 TCP large packets.
+ */
+static int msdn_giant_send_check(struct sk_buff *skb)
+{
+       const struct ipv6hdr *ipv6h;
+       struct tcphdr *th;
+       int ret;
+
+       ret = skb_cow_head(skb, 0);
+       if (ret)
+               return ret;
+
+       ipv6h = ipv6_hdr(skb);
+       th = tcp_hdr(skb);
+
+       th->check = 0;
+       th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0);
+
+       return ret;
+}
+
+static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
+                        struct sk_buff *skb, u32 len, u32 transport_offset)
+{
+       u32 mss = skb_shinfo(skb)->gso_size;
+       u32 opts1, opts2 = 0;
+       int ret = TX_CSUM_SUCCESS;
+
+       WARN_ON_ONCE(len > TX_LEN_MAX);
+
+       opts1 = len | TX_FS | TX_LS;
+
+       if (mss) {
+               if (transport_offset > GTTCPHO_MAX) {
+                       netif_warn(tp, tx_err, tp->netdev,
+                                  "Invalid transport offset 0x%x for TSO\n",
+                                  transport_offset);
+                       ret = TX_CSUM_TSO;
+                       goto unavailable;
+               }
+
+               switch (get_protocol(skb)) {
+               case htons(ETH_P_IP):
+                       opts1 |= GTSENDV4;
+                       break;
+
+               case htons(ETH_P_IPV6):
+                       if (msdn_giant_send_check(skb)) {
+                               ret = TX_CSUM_TSO;
+                               goto unavailable;
+                       }
+                       opts1 |= GTSENDV6;
+                       break;
+
+               default:
+                       WARN_ON_ONCE(1);
+                       break;
+               }
+
+               opts1 |= transport_offset << GTTCPHO_SHIFT;
+               opts2 |= min(mss, MSS_MAX) << MSS_SHIFT;
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                u8 ip_protocol;
-               u32 opts2 = 0;
 
-               if (skb->protocol == htons(ETH_P_8021Q))
-                       protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
-               else
-                       protocol = skb->protocol;
+               if (transport_offset > TCPHO_MAX) {
+                       netif_warn(tp, tx_err, tp->netdev,
+                                  "Invalid transport offset 0x%x\n",
+                                  transport_offset);
+                       ret = TX_CSUM_NONE;
+                       goto unavailable;
+               }
 
-               switch (protocol) {
+               switch (get_protocol(skb)) {
                case htons(ETH_P_IP):
                        opts2 |= IPV4_CS;
                        ip_protocol = ip_hdr(skb)->protocol;
@@ -1316,30 +1477,33 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
                        break;
                }
 
-               if (ip_protocol == IPPROTO_TCP) {
+               if (ip_protocol == IPPROTO_TCP)
                        opts2 |= TCP_CS;
-                       opts2 |= (skb_transport_offset(skb) & 0x7fff) << 17;
-               } else if (ip_protocol == IPPROTO_UDP) {
+               else if (ip_protocol == IPPROTO_UDP)
                        opts2 |= UDP_CS;
-               } else {
+               else
                        WARN_ON_ONCE(1);
-               }
 
-               desc->opts2 = cpu_to_le32(opts2);
+               opts2 |= transport_offset << TCPHO_SHIFT;
        }
+
+       desc->opts2 = cpu_to_le32(opts2);
+       desc->opts1 = cpu_to_le32(opts1);
+
+unavailable:
+       return ret;
 }
 
 static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
 {
        struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue;
-       unsigned long flags;
        int remain, ret;
        u8 *tx_data;
 
        __skb_queue_head_init(&skb_head);
-       spin_lock_irqsave(&tx_queue->lock, flags);
+       spin_lock(&tx_queue->lock);
        skb_queue_splice_init(tx_queue, &skb_head);
-       spin_unlock_irqrestore(&tx_queue->lock, flags);
+       spin_unlock(&tx_queue->lock);
 
        tx_data = agg->head;
        agg->skb_num = agg->skb_len = 0;
@@ -1349,47 +1513,65 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
                struct tx_desc *tx_desc;
                struct sk_buff *skb;
                unsigned int len;
+               u32 offset;
 
                skb = __skb_dequeue(&skb_head);
                if (!skb)
                        break;
 
-               remain -= sizeof(*tx_desc);
-               len = skb->len;
-               if (remain < len) {
+               len = skb->len + sizeof(*tx_desc);
+
+               if (len > remain) {
                        __skb_queue_head(&skb_head, skb);
                        break;
                }
 
                tx_data = tx_agg_align(tx_data);
                tx_desc = (struct tx_desc *)tx_data;
+
+               offset = (u32)skb_transport_offset(skb);
+
+               if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) {
+                       r8152_csum_workaround(tp, skb, &skb_head);
+                       continue;
+               }
+
                tx_data += sizeof(*tx_desc);
 
-               r8152_tx_csum(tp, tx_desc, skb);
-               memcpy(tx_data, skb->data, len);
-               agg->skb_num++;
+               len = skb->len;
+               if (skb_copy_bits(skb, 0, tx_data, len) < 0) {
+                       struct net_device_stats *stats = &tp->netdev->stats;
+
+                       stats->tx_dropped++;
+                       dev_kfree_skb_any(skb);
+                       tx_data -= sizeof(*tx_desc);
+                       continue;
+               }
+
+               tx_data += len;
                agg->skb_len += len;
+               agg->skb_num++;
+
                dev_kfree_skb_any(skb);
 
-               tx_data += len;
                remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
        }
 
        if (!skb_queue_empty(&skb_head)) {
-               spin_lock_irqsave(&tx_queue->lock, flags);
+               spin_lock(&tx_queue->lock);
                skb_queue_splice(&skb_head, tx_queue);
-               spin_unlock_irqrestore(&tx_queue->lock, flags);
+               spin_unlock(&tx_queue->lock);
        }
 
-       netif_tx_lock_bh(tp->netdev);
+       netif_tx_lock(tp->netdev);
 
        if (netif_queue_stopped(tp->netdev) &&
            skb_queue_len(&tp->tx_queue) < tp->tx_qlen)
                netif_wake_queue(tp->netdev);
 
-       netif_tx_unlock_bh(tp->netdev);
+       netif_tx_unlock(tp->netdev);
 
-       ret = usb_autopm_get_interface(tp->intf);
+       ret = usb_autopm_get_interface_async(tp->intf);
        if (ret < 0)
                goto out_tx_fill;
 
@@ -1397,14 +1579,45 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
                          agg->head, (int)(tx_data - (u8 *)agg->head),
                          (usb_complete_t)write_bulk_callback, agg);
 
-       ret = usb_submit_urb(agg->urb, GFP_KERNEL);
+       ret = usb_submit_urb(agg->urb, GFP_ATOMIC);
        if (ret < 0)
-               usb_autopm_put_interface(tp->intf);
+               usb_autopm_put_interface_async(tp->intf);
 
 out_tx_fill:
        return ret;
 }
 
+static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
+{
+       u8 checksum = CHECKSUM_NONE;
+       u32 opts2, opts3;
+
+       if (tp->version == RTL_VER_01)
+               goto return_result;
+
+       opts2 = le32_to_cpu(rx_desc->opts2);
+       opts3 = le32_to_cpu(rx_desc->opts3);
+
+       if (opts2 & RD_IPV4_CS) {
+               if (opts3 & IPF)
+                       checksum = CHECKSUM_NONE;
+               else if ((opts2 & RD_UDP_CS) && (opts3 & UDPF))
+                       checksum = CHECKSUM_NONE;
+               else if ((opts2 & RD_TCP_CS) && (opts3 & TCPF))
+                       checksum = CHECKSUM_NONE;
+               else
+                       checksum = CHECKSUM_UNNECESSARY;
+       } else if (RD_IPV6_CS) {
+               if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF))
+                       checksum = CHECKSUM_UNNECESSARY;
+               else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF))
+                       checksum = CHECKSUM_UNNECESSARY;
+       }
+
+return_result:
+       return checksum;
+}
+
 static void rx_bottom(struct r8152 *tp)
 {
        unsigned long flags;
@@ -1439,7 +1652,7 @@ static void rx_bottom(struct r8152 *tp)
 
                while (urb->actual_length > len_used) {
                        struct net_device *netdev = tp->netdev;
-                       struct net_device_stats *stats;
+                       struct net_device_stats *stats = &netdev->stats;
                        unsigned int pkt_len;
                        struct sk_buff *skb;
 
@@ -1451,16 +1664,16 @@ static void rx_bottom(struct r8152 *tp)
                        if (urb->actual_length < len_used)
                                break;
 
-                       stats = rtl8152_get_stats(netdev);
-
                        pkt_len -= CRC_SIZE;
                        rx_data += sizeof(struct rx_desc);
 
                        skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
                        if (!skb) {
                                stats->rx_dropped++;
-                               break;
+                               goto find_next_rx;
                        }
+
+                       skb->ip_summed = r8152_rx_csum(tp, rx_desc);
                        memcpy(skb->data, rx_data, pkt_len);
                        skb_put(skb, pkt_len);
                        skb->protocol = eth_type_trans(skb, netdev);
@@ -1468,6 +1681,7 @@ static void rx_bottom(struct r8152 *tp)
                        stats->rx_packets++;
                        stats->rx_bytes += pkt_len;
 
+find_next_rx:
                        rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE);
                        rx_desc = (struct rx_desc *)rx_data;
                        len_used = (int)(rx_data - (u8 *)agg->head);
@@ -1501,19 +1715,18 @@ static void tx_bottom(struct r8152 *tp)
 
                res = r8152_tx_agg_fill(tp, agg);
                if (res) {
-                       struct net_device_stats *stats;
-                       struct net_device *netdev;
-                       unsigned long flags;
-
-                       netdev = tp->netdev;
-                       stats = rtl8152_get_stats(netdev);
+                       struct net_device *netdev = tp->netdev;
 
                        if (res == -ENODEV) {
                                netif_device_detach(netdev);
                        } else {
+                               struct net_device_stats *stats = &netdev->stats;
+                               unsigned long flags;
+
                                netif_warn(tp, tx_err, netdev,
                                           "failed tx_urb %d\n", res);
                                stats->tx_dropped += agg->skb_num;
+
                                spin_lock_irqsave(&tp->tx_lock, flags);
                                list_add_tail(&agg->list, &tp->tx_free);
                                spin_unlock_irqrestore(&tp->tx_lock, flags);
@@ -1540,6 +1753,7 @@ static void bottom_half(unsigned long data)
                return;
 
        rx_bottom(tp);
+       tx_bottom(tp);
 }
 
 static
@@ -1556,16 +1770,15 @@ static void rtl_drop_queued_tx(struct r8152 *tp)
 {
        struct net_device_stats *stats = &tp->netdev->stats;
        struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue;
-       unsigned long flags;
        struct sk_buff *skb;
 
        if (skb_queue_empty(tx_queue))
                return;
 
        __skb_queue_head_init(&skb_head);
-       spin_lock_irqsave(&tx_queue->lock, flags);
+       spin_lock_bh(&tx_queue->lock);
        skb_queue_splice_init(tx_queue, &skb_head);
-       spin_unlock_irqrestore(&tx_queue->lock, flags);
+       spin_unlock_bh(&tx_queue->lock);
 
        while ((skb = __skb_dequeue(&skb_head))) {
                dev_kfree_skb(skb);
@@ -1636,7 +1849,7 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
 }
 
 static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
-                                           struct net_device *netdev)
+                                       struct net_device *netdev)
 {
        struct r8152 *tp = netdev_priv(netdev);
 
@@ -1644,13 +1857,17 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
 
        skb_queue_tail(&tp->tx_queue, skb);
 
-       if (list_empty(&tp->tx_free) &&
-           skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
+       if (!list_empty(&tp->tx_free)) {
+               if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+                       set_bit(SCHEDULE_TASKLET, &tp->flags);
+                       schedule_delayed_work(&tp->schedule, 0);
+               } else {
+                       usb_mark_last_busy(tp->udev);
+                       tasklet_schedule(&tp->tl);
+               }
+       } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
                netif_stop_queue(netdev);
 
-       if (!list_empty(&tp->tx_free))
-               schedule_delayed_work(&tp->schedule, 0);
-
        return NETDEV_TX_OK;
 }
 
@@ -1833,7 +2050,6 @@ static void r8152_power_cut_en(struct r8152 *tp, bool enable)
        ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
        ocp_data &= ~RESUME_INDICATE;
        ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
-
 }
 
 #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
@@ -2013,8 +2229,8 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp)
 
 static void r8152b_exit_oob(struct r8152 *tp)
 {
-       u32     ocp_data;
-       int     i;
+       u32 ocp_data;
+       int i;
 
        ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
        ocp_data &= ~RCR_ACPT_ALL;
@@ -2530,8 +2746,11 @@ static void rtl_work_func_t(struct work_struct *work)
        if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
                _rtl8152_set_rx_mode(tp->netdev);
 
-       if (tp->speed & LINK_STATUS)
-               tx_bottom(tp);
+       if (test_bit(SCHEDULE_TASKLET, &tp->flags) &&
+           (tp->speed & LINK_STATUS)) {
+               clear_bit(SCHEDULE_TASKLET, &tp->flags);
+               tasklet_schedule(&tp->tl);
+       }
 
        if (test_bit(PHY_RESET, &tp->flags))
                rtl_phy_reset(tp);
@@ -2573,6 +2792,7 @@ static int rtl8152_open(struct net_device *netdev)
        netif_carrier_off(netdev);
        netif_start_queue(netdev);
        set_bit(WORK_ENABLE, &tp->flags);
+
        res = usb_submit_urb(tp->intr_urb, GFP_KERNEL);
        if (res) {
                if (res == -ENODEV)
@@ -2671,6 +2891,15 @@ static void r8152b_enable_fc(struct r8152 *tp)
        r8152_mdio_write(tp, MII_ADVERTISE, anar);
 }
 
+static void rtl_tally_reset(struct r8152 *tp)
+{
+       u32 ocp_data;
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY);
+       ocp_data |= TALLY_RESET;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
+}
+
 static void r8152b_init(struct r8152 *tp)
 {
        u32 ocp_data;
@@ -2697,6 +2926,7 @@ static void r8152b_init(struct r8152 *tp)
        r8152b_enable_eee(tp);
        r8152b_enable_aldps(tp);
        r8152b_enable_fc(tp);
+       rtl_tally_reset(tp);
 
        /* enable rx aggregation */
        ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
@@ -2764,6 +2994,7 @@ static void r8153_init(struct r8152 *tp)
        r8153_enable_eee(tp);
        r8153_enable_aldps(tp);
        r8152b_enable_fc(tp);
+       rtl_tally_reset(tp);
 }
 
 static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
@@ -2904,6 +3135,64 @@ out:
        return ret;
 }
 
+static const char rtl8152_gstrings[][ETH_GSTRING_LEN] = {
+       "tx_packets",
+       "rx_packets",
+       "tx_errors",
+       "rx_errors",
+       "rx_missed",
+       "align_errors",
+       "tx_single_collisions",
+       "tx_multi_collisions",
+       "rx_unicast",
+       "rx_broadcast",
+       "rx_multicast",
+       "tx_aborted",
+       "tx_underrun",
+};
+
+static int rtl8152_get_sset_count(struct net_device *dev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(rtl8152_gstrings);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void rtl8152_get_ethtool_stats(struct net_device *dev,
+                                     struct ethtool_stats *stats, u64 *data)
+{
+       struct r8152 *tp = netdev_priv(dev);
+       struct tally_counter tally;
+
+       generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA);
+
+       data[0] = le64_to_cpu(tally.tx_packets);
+       data[1] = le64_to_cpu(tally.rx_packets);
+       data[2] = le64_to_cpu(tally.tx_errors);
+       data[3] = le32_to_cpu(tally.rx_errors);
+       data[4] = le16_to_cpu(tally.rx_missed);
+       data[5] = le16_to_cpu(tally.align_errors);
+       data[6] = le32_to_cpu(tally.tx_one_collision);
+       data[7] = le32_to_cpu(tally.tx_multi_collision);
+       data[8] = le64_to_cpu(tally.rx_unicast);
+       data[9] = le64_to_cpu(tally.rx_broadcast);
+       data[10] = le32_to_cpu(tally.rx_multicast);
+       data[11] = le16_to_cpu(tally.tx_aborted);
+       data[12] = le16_to_cpu(tally.tx_underun);
+}
+
+static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       switch (stringset) {
+       case ETH_SS_STATS:
+               memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings));
+               break;
+       }
+}
+
 static struct ethtool_ops ops = {
        .get_drvinfo = rtl8152_get_drvinfo,
        .get_settings = rtl8152_get_settings,
@@ -2913,6 +3202,9 @@ static struct ethtool_ops ops = {
        .set_msglevel = rtl8152_set_msglevel,
        .get_wol = rtl8152_get_wol,
        .set_wol = rtl8152_set_wol,
+       .get_strings = rtl8152_get_strings,
+       .get_sset_count = rtl8152_get_sset_count,
+       .get_ethtool_stats = rtl8152_get_ethtool_stats,
 };
 
 static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -3075,6 +3367,12 @@ 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;
+       }
+
+       usb_reset_device(udev);
        netdev = alloc_etherdev(sizeof(struct r8152));
        if (!netdev) {
                dev_err(&intf->dev, "Out of memory\n");
@@ -3099,9 +3397,15 @@ static int rtl8152_probe(struct usb_interface *intf,
        netdev->netdev_ops = &rtl8152_netdev_ops;
        netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;
 
-       netdev->features |= NETIF_F_IP_CSUM;
-       netdev->hw_features = NETIF_F_IP_CSUM;
+       netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
+                           NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM |
+                           NETIF_F_TSO6;
+       netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
+                             NETIF_F_TSO | NETIF_F_FRAGLIST |
+                             NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
+
        SET_ETHTOOL_OPS(netdev, &ops);
+       netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE);
 
        tp->mii.dev = netdev;
        tp->mii.mdio_read = read_mii_word;
@@ -3158,9 +3462,9 @@ static void rtl8152_disconnect(struct usb_interface *intf)
 
 /* table of devices that work with this driver */
 static struct usb_device_id rtl8152_table[] = {
-       {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)},
+       {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
+       {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
+       {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
        {}
 };
 
diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
deleted file mode 100644 (file)
index f0a8791..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/mii.h>
-#include <linux/usb.h>
-#include <linux/usb/cdc.h>
-#include <linux/usb/usbnet.h>
-
-#define RTL815x_REQT_READ      0xc0
-#define RTL815x_REQT_WRITE     0x40
-#define RTL815x_REQ_GET_REGS   0x05
-#define RTL815x_REQ_SET_REGS   0x05
-
-#define MCU_TYPE_PLA           0x0100
-#define OCP_BASE               0xe86c
-#define BASE_MII               0xa400
-
-#define BYTE_EN_DWORD          0xff
-#define BYTE_EN_WORD           0x33
-#define BYTE_EN_BYTE           0x11
-
-#define R815x_PHY_ID           32
-#define REALTEK_VENDOR_ID      0x0bda
-
-
-static int pla_read_word(struct usb_device *udev, u16 index)
-{
-       int ret;
-       u8 shift = index & 2;
-       __le32 *tmp;
-
-       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-       if (!tmp)
-               return -ENOMEM;
-
-       index &= ~3;
-
-       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                             RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
-       if (ret < 0)
-               goto out2;
-
-       ret = __le32_to_cpu(*tmp);
-       ret >>= (shift * 8);
-       ret &= 0xffff;
-
-out2:
-       kfree(tmp);
-       return ret;
-}
-
-static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
-{
-       __le32 *tmp;
-       u32 mask = 0xffff;
-       u16 byen = BYTE_EN_WORD;
-       u8 shift = index & 2;
-       int ret;
-
-       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-       if (!tmp)
-               return -ENOMEM;
-
-       data &= mask;
-
-       if (shift) {
-               byen <<= shift;
-               mask <<= (shift * 8);
-               data <<= (shift * 8);
-               index &= ~3;
-       }
-
-       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                             RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
-       if (ret < 0)
-               goto out3;
-
-       data |= __le32_to_cpu(*tmp) & ~mask;
-       *tmp = __cpu_to_le32(data);
-
-       ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                             RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
-                             index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
-                             500);
-
-out3:
-       kfree(tmp);
-       return ret;
-}
-
-static int ocp_reg_read(struct usbnet *dev, u16 addr)
-{
-       u16 ocp_base, ocp_index;
-       int ret;
-
-       ocp_base = addr & 0xf000;
-       ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
-       if (ret < 0)
-               goto out;
-
-       ocp_index = (addr & 0x0fff) | 0xb000;
-       ret = pla_read_word(dev->udev, ocp_index);
-
-out:
-       return ret;
-}
-
-static int ocp_reg_write(struct usbnet *dev, u16 addr, u16 data)
-{
-       u16 ocp_base, ocp_index;
-       int ret;
-
-       ocp_base = addr & 0xf000;
-       ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
-       if (ret < 0)
-               goto out1;
-
-       ocp_index = (addr & 0x0fff) | 0xb000;
-       ret = pla_write_word(dev->udev, ocp_index, data);
-
-out1:
-       return ret;
-}
-
-static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
-{
-       struct usbnet *dev = netdev_priv(netdev);
-       int ret;
-
-       if (phy_id != R815x_PHY_ID)
-               return -EINVAL;
-
-       if (usb_autopm_get_interface(dev->intf) < 0)
-               return -ENODEV;
-
-       ret = ocp_reg_read(dev, BASE_MII + reg * 2);
-
-       usb_autopm_put_interface(dev->intf);
-       return ret;
-}
-
-static
-void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
-{
-       struct usbnet *dev = netdev_priv(netdev);
-
-       if (phy_id != R815x_PHY_ID)
-               return;
-
-       if (usb_autopm_get_interface(dev->intf) < 0)
-               return;
-
-       ocp_reg_write(dev, BASE_MII + reg * 2, val);
-
-       usb_autopm_put_interface(dev->intf);
-}
-
-static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
-{
-       int status;
-
-       status = usbnet_cdc_bind(dev, intf);
-       if (status < 0)
-               return status;
-
-       dev->mii.dev = dev->net;
-       dev->mii.mdio_read = r815x_mdio_read;
-       dev->mii.mdio_write = r815x_mdio_write;
-       dev->mii.phy_id_mask = 0x3f;
-       dev->mii.reg_num_mask = 0x1f;
-       dev->mii.phy_id = R815x_PHY_ID;
-       dev->mii.supports_gmii = 1;
-
-       return status;
-}
-
-static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
-{
-       int status;
-
-       status = usbnet_cdc_bind(dev, intf);
-       if (status < 0)
-               return status;
-
-       dev->mii.dev = dev->net;
-       dev->mii.mdio_read = r815x_mdio_read;
-       dev->mii.mdio_write = r815x_mdio_write;
-       dev->mii.phy_id_mask = 0x3f;
-       dev->mii.reg_num_mask = 0x1f;
-       dev->mii.phy_id = R815x_PHY_ID;
-       dev->mii.supports_gmii = 0;
-
-       return status;
-}
-
-static const struct driver_info r8152_info = {
-       .description =  "RTL8152 ECM Device",
-       .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
-       .bind =         r8152_bind,
-       .unbind =       usbnet_cdc_unbind,
-       .status =       usbnet_cdc_status,
-       .manage_power = usbnet_manage_power,
-};
-
-static const struct driver_info r8153_info = {
-       .description =  "RTL8153 ECM Device",
-       .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
-       .bind =         r8153_bind,
-       .unbind =       usbnet_cdc_unbind,
-       .status =       usbnet_cdc_status,
-       .manage_power = usbnet_manage_power,
-};
-
-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),
-       .driver_info = (unsigned long) &r8152_info,
-},
-
-{
-       USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &r8153_info,
-},
-
-       { },            /* END */
-};
-MODULE_DEVICE_TABLE(usb, products);
-
-static struct usb_driver r815x_driver = {
-       .name =         "r815x",
-       .id_table =     products,
-       .probe =        usbnet_probe,
-       .disconnect =   usbnet_disconnect,
-       .suspend =      usbnet_suspend,
-       .resume =       usbnet_resume,
-       .reset_resume = usbnet_resume,
-       .supports_autosuspend = 1,
-       .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(r815x_driver);
-
-MODULE_AUTHOR("Hayes Wang");
-MODULE_DESCRIPTION("Realtek USB ECM device");
-MODULE_LICENSE("GPL");
index 34b52638e12d42fc7f50fec9d10c7bc66768cbef..e1c77d4b80e4e967bef4a38bea2bdf1e907c7e2e 100644 (file)
@@ -156,10 +156,10 @@ static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev)
                unsigned int start;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&stats->syncp);
                        packets = stats->packets;
                        bytes = stats->bytes;
-               } while (u64_stats_fetch_retry_bh(&stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
                result->packets += packets;
                result->bytes += bytes;
        }
@@ -277,7 +277,8 @@ static void veth_setup(struct net_device *dev)
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
        dev->features |= VETH_FEATURES;
-       dev->vlan_features = dev->features;
+       dev->vlan_features = dev->features &
+                            ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX);
        dev->destructor = veth_dev_free;
 
        dev->hw_features = VETH_FEATURES;
index d75f8edf4fb370300d13bd22adcfe66e754fb5a2..80d84c446962362ba6d6124d43e8ec7bd753aef0 100644 (file)
@@ -1000,16 +1000,16 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
                u64 tpackets, tbytes, rpackets, rbytes;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->tx_syncp);
+                       start = u64_stats_fetch_begin_irq(&stats->tx_syncp);
                        tpackets = stats->tx_packets;
                        tbytes   = stats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&stats->tx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&stats->tx_syncp, start));
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->rx_syncp);
+                       start = u64_stats_fetch_begin_irq(&stats->rx_syncp);
                        rpackets = stats->rx_packets;
                        rbytes   = stats->rx_bytes;
-               } while (u64_stats_fetch_retry_bh(&stats->rx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&stats->rx_syncp, start));
 
                tot->rx_packets += rpackets;
                tot->tx_packets += tpackets;
@@ -1711,7 +1711,8 @@ static int virtnet_probe(struct virtio_device *vdev)
        /* If we can receive ANY GSO packets, we must allocate large ones. */
        if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
            virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
-           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
+           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
+           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
                vi->big_packets = true;
 
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
index 9275c8c423b14e70382b92020d5617462c03e8d2..28965adfeebd353195cae206b83471296030df73 100644 (file)
@@ -1762,11 +1762,20 @@ vmxnet3_netpoll(struct net_device *netdev)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
 
-       if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
-               vmxnet3_disable_all_intrs(adapter);
-
-       vmxnet3_do_poll(adapter, adapter->rx_queue[0].rx_ring[0].size);
-       vmxnet3_enable_all_intrs(adapter);
+       switch (adapter->intr.type) {
+#ifdef CONFIG_PCI_MSI
+       case VMXNET3_IT_MSIX: {
+               int i;
+               for (i = 0; i < adapter->num_rx_queues; i++)
+                       vmxnet3_msix_rx(0, &adapter->rx_queue[i]);
+               break;
+       }
+#endif
+       case VMXNET3_IT_MSI:
+       default:
+               vmxnet3_intr(0, adapter->netdev);
+               break;
+       }
 
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
index 200020eb30059d73767a8cda2540b4f9af9326cf..d1fab435f5a3fb1e40c9defda34f794f1903b83d 100644 (file)
@@ -53,7 +53,7 @@ config LIBERTAS_THINFIRM_USB
 
 config AIRO
        tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
-       depends on ISA_DMA_API && (PCI || BROKEN)
+       depends on CFG80211 && ISA_DMA_API && (PCI || BROKEN)
        select WIRELESS_EXT
        select CRYPTO
        select WEXT_SPY
@@ -73,7 +73,7 @@ config AIRO
 
 config ATMEL
       tristate "Atmel at76c50x chipset  802.11b support"
-      depends on (PCI || PCMCIA)
+      depends on CFG80211 && (PCI || PCMCIA)
       select WIRELESS_EXT
       select WEXT_PRIV
       select FW_LOADER
@@ -138,7 +138,7 @@ config AIRO_CS
 
 config PCMCIA_WL3501
        tristate "Planet WL3501 PCMCIA cards"
-       depends on PCMCIA
+       depends on CFG80211 && PCMCIA
        select WIRELESS_EXT
        select WEXT_SPY
        help
@@ -168,7 +168,7 @@ config PRISM54
 
 config USB_ZD1201
        tristate "USB ZD1201 based Wireless device support"
-       depends on USB
+       depends on CFG80211 && USB
        select WIRELESS_EXT
        select WEXT_PRIV
        select FW_LOADER
index edf4b57c4aaa306ebbf12beea5100d6f6a7f5e2e..64747d457bb3a1879f9cb0b478836dea4cb3099e 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/bitops.h>
 #include <linux/scatterlist.h>
 #include <linux/crypto.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/unaligned.h>
 
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
-#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
 #include <net/iw_handler.h>
 
 #include "airo.h"
@@ -5797,7 +5797,7 @@ static int airo_set_freq(struct net_device *dev,
 
                /* Hack to fall through... */
                fwrq->e = 0;
-               fwrq->m = ieee80211_freq_to_dsss_chan(f);
+               fwrq->m = ieee80211_frequency_to_channel(f);
        }
        /* Setting by channel number */
        if((fwrq->m > 1000) || (fwrq->e > 0))
@@ -5841,7 +5841,8 @@ static int airo_get_freq(struct net_device *dev,
 
        ch = le16_to_cpu(status_rid.channel);
        if((ch > 0) && (ch < 15)) {
-               fwrq->m = ieee80211_dsss_chan_to_freq(ch) * 100000;
+               fwrq->m = 100000 *
+                       ieee80211_channel_to_frequency(ch, IEEE80211_BAND_2GHZ);
                fwrq->e = 1;
        } else {
                fwrq->m = ch;
@@ -6898,7 +6899,8 @@ static int airo_get_range(struct net_device *dev,
        k = 0;
        for(i = 0; i < 14; i++) {
                range->freq[k].i = i + 1; /* List index */
-               range->freq[k].m = ieee80211_dsss_chan_to_freq(i + 1) * 100000;
+               range->freq[k].m = 100000 *
+                    ieee80211_channel_to_frequency(i + 1, IEEE80211_BAND_2GHZ);
                range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */
        }
        range->num_frequency = k;
@@ -7297,7 +7299,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
        /* Add frequency */
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
-       iwe.u.freq.m = ieee80211_dsss_chan_to_freq(iwe.u.freq.m) * 100000;
+       iwe.u.freq.m = 100000 *
+             ieee80211_channel_to_frequency(iwe.u.freq.m, IEEE80211_BAND_2GHZ);
        iwe.u.freq.e = 1;
        current_ev = iwe_stream_add_event(info, current_ev, end_buf,
                                          &iwe, IW_EV_FREQ_LEN);
index 6260b834a86f0365c7e3db9f4d72fe2273964dac..d239acc261256fcbb7225826448976edbca08963 100644 (file)
@@ -63,7 +63,7 @@ enum ath_bus_type {
 };
 
 struct reg_dmn_pair_mapping {
-       u16 regDmnEnum;
+       u16 reg_domain;
        u16 reg_5ghz_ctl;
        u16 reg_2ghz_ctl;
 };
@@ -163,6 +163,7 @@ struct ath_common {
        bool bt_ant_diversity;
 
        int last_rssi;
+       struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
 };
 
 struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
index 3b59af3bddf4a6e4506f027472c41832f41c43c9..ebc5fc2ede75cbac75da3a2f789a946d4e1274ad 100644 (file)
@@ -55,8 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
 {
        ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
 
-       ar->is_target_paused = true;
-       wake_up(&ar->event_queue);
+       complete(&ar->target_suspend);
 }
 
 static int ath10k_init_connect_htc(struct ath10k *ar)
@@ -470,8 +469,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                                if (index == ie_len)
                                        break;
 
-                               if (data[index] & (1 << bit))
+                               if (data[index] & (1 << bit)) {
+                                       ath10k_dbg(ATH10K_DBG_BOOT,
+                                                  "Enabling feature bit: %i\n",
+                                                  i);
                                        __set_bit(i, ar->fw_features);
+                               }
                        }
 
                        ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
@@ -699,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
        init_completion(&ar->scan.started);
        init_completion(&ar->scan.completed);
        init_completion(&ar->scan.on_channel);
+       init_completion(&ar->target_suspend);
 
        init_completion(&ar->install_key_done);
        init_completion(&ar->vdev_setup_done);
@@ -722,8 +726,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
        INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
        skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
 
-       init_waitqueue_head(&ar->event_queue);
-
        INIT_WORK(&ar->restart_work, ath10k_core_restart);
 
        return ar;
@@ -856,10 +858,34 @@ err:
 }
 EXPORT_SYMBOL(ath10k_core_start);
 
+int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
+{
+       int ret;
+
+       reinit_completion(&ar->target_suspend);
+
+       ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);
+       if (ret) {
+               ath10k_warn("could not suspend target (%d)\n", ret);
+               return ret;
+       }
+
+       ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
+
+       if (ret == 0) {
+               ath10k_warn("suspend timed out - target pause event never came\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
 void ath10k_core_stop(struct ath10k *ar)
 {
        lockdep_assert_held(&ar->conf_mutex);
 
+       /* try to suspend target */
+       ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
        ath10k_debug_stop(ar);
        ath10k_htc_stop(&ar->htc);
        ath10k_htt_detach(&ar->htt);
index ade1781c7186c5d033a0d5bc5dda2c36b4c6a4ac..1fc26fe057e80bd760d0ef9b6a132679353b41be 100644 (file)
 
 #define ATH10K_MAX_NUM_MGMT_PENDING 128
 
+/* number of failed packets */
+#define ATH10K_KICKOUT_THRESHOLD 50
+
+/*
+ * Use insanely high numbers to make sure that the firmware implementation
+ * won't start, we have the same functionality already in hostapd. Unit
+ * is seconds.
+ */
+#define ATH10K_KEEPALIVE_MIN_IDLE 3747
+#define ATH10K_KEEPALIVE_MAX_IDLE 3895
+#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900
+
 struct ath10k;
 
 struct ath10k_skb_cb {
@@ -61,6 +73,11 @@ struct ath10k_skb_cb {
                u8 frag_len;
                u8 pad_len;
        } __packed htt;
+
+       struct {
+               bool dtim_zero;
+               bool deliver_cab;
+       } bcn;
 } __packed;
 
 static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
@@ -211,6 +228,18 @@ struct ath10k_peer {
        struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
 };
 
+struct ath10k_sta {
+       struct ath10k_vif *arvif;
+
+       /* the following are protected by ar->data_lock */
+       u32 changed; /* IEEE80211_RC_* */
+       u32 bw;
+       u32 nss;
+       u32 smps;
+
+       struct work_struct update_wk;
+};
+
 #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
 
 struct ath10k_vif {
@@ -222,10 +251,17 @@ struct ath10k_vif {
        u32 beacon_interval;
        u32 dtim_period;
        struct sk_buff *beacon;
+       /* protected by data_lock */
+       bool beacon_sent;
 
        struct ath10k *ar;
        struct ieee80211_vif *vif;
 
+       bool is_started;
+       bool is_up;
+       u32 aid;
+       u8 bssid[ETH_ALEN];
+
        struct work_struct wep_key_work;
        struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
        u8 def_wep_key_idx;
@@ -235,7 +271,6 @@ struct ath10k_vif {
 
        union {
                struct {
-                       u8 bssid[ETH_ALEN];
                        u32 uapsd;
                } sta;
                struct {
@@ -249,9 +284,6 @@ struct ath10k_vif {
                        u32 noa_len;
                        u8 *noa_data;
                } ap;
-               struct {
-                       u8 bssid[ETH_ALEN];
-               } ibss;
        } u;
 
        u8 fixed_rate;
@@ -355,8 +387,7 @@ struct ath10k {
                const struct ath10k_hif_ops *ops;
        } hif;
 
-       wait_queue_head_t event_queue;
-       bool is_target_paused;
+       struct completion target_suspend;
 
        struct ath10k_bmi bmi;
        struct ath10k_wmi wmi;
@@ -412,6 +443,9 @@ struct ath10k {
        /* valid during scan; needed for mgmt rx during scan */
        struct ieee80211_channel *scan_channel;
 
+       /* current operating channel definition */
+       struct cfg80211_chan_def chandef;
+
        int free_vdev_map;
        int monitor_vdev_id;
        bool monitor_enabled;
@@ -470,6 +504,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
 void ath10k_core_destroy(struct ath10k *ar);
 
 int ath10k_core_start(struct ath10k *ar);
+int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
 void ath10k_core_stop(struct ath10k *ar);
 int ath10k_core_register(struct ath10k *ar, u32 chip_id);
 void ath10k_core_unregister(struct ath10k *ar);
index 1773c36c71a01a179177b887a3485c9f05c505cf..a5824990bd2a8c789e69d18bb2e3f12f26548248 100644 (file)
@@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
 
 #ifdef CONFIG_ATH10K_DEBUG
 __printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
-                                     const char *fmt, ...);
+                              const char *fmt, ...);
 void ath10k_dbg_dump(enum ath10k_debug_mask mask,
                     const char *msg, const char *prefix,
                     const void *buf, size_t len);
index fe8bd1b59f0e2651ee27b742087aedeb5e96a56c..4767c24bf8194113b7e89ea77930efa93e3a701b 100644 (file)
@@ -324,7 +324,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
                                 msdu->len + skb_tailroom(msdu),
                                 DMA_FROM_DEVICE);
 
-               ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ",
+               ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
                                msdu->data, msdu->len + skb_tailroom(msdu));
 
                rx_desc = (struct htt_rx_desc *)msdu->data;
@@ -417,8 +417,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
                                         next->len + skb_tailroom(next),
                                         DMA_FROM_DEVICE);
 
-                       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ",
-                                       next->data,
+                       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
+                                       "htt rx chained: ", next->data,
                                        next->len + skb_tailroom(next));
 
                        skb_trim(next, 0);
@@ -430,12 +430,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
                        msdu_chaining = 1;
                }
 
-               if (msdu_len > 0) {
-                       /* This may suggest FW bug? */
-                       ath10k_warn("htt rx msdu len not consumed (%d)\n",
-                                   msdu_len);
-               }
-
                last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
                                RX_MSDU_END_INFO0_LAST_MSDU;
 
@@ -751,7 +745,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
 
        /* This shouldn't happen. If it does than it may be a FW bug. */
        if (skb->next) {
-               ath10k_warn("received chained non A-MSDU frame\n");
+               ath10k_warn("htt rx received chained non A-MSDU frame\n");
                ath10k_htt_rx_free_msdu_chain(skb->next);
                skb->next = NULL;
        }
@@ -937,6 +931,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                        }
 
                        if (ath10k_htt_rx_has_decrypt_err(msdu_head)) {
+                               ath10k_dbg(ATH10K_DBG_HTT,
+                                          "htt rx dropping due to decrypt-err\n");
                                ath10k_htt_rx_free_msdu_chain(msdu_head);
                                continue;
                        }
@@ -945,12 +941,14 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 
                        /* Skip mgmt frames while we handle this in WMI */
                        if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL) {
+                               ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
                                ath10k_htt_rx_free_msdu_chain(msdu_head);
                                continue;
                        }
 
                        if (status != HTT_RX_IND_MPDU_STATUS_OK &&
                            status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
+                           status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
                            !htt->ar->monitor_enabled) {
                                ath10k_dbg(ATH10K_DBG_HTT,
                                           "htt rx ignoring frame w/ status %d\n",
@@ -960,6 +958,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                        }
 
                        if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
+                               ath10k_dbg(ATH10K_DBG_HTT,
+                                          "htt rx CAC running\n");
                                ath10k_htt_rx_free_msdu_chain(msdu_head);
                                continue;
                        }
@@ -967,7 +967,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                        /* FIXME: we do not support chaining yet.
                         * this needs investigation */
                        if (msdu_chaining) {
-                               ath10k_warn("msdu_chaining is true\n");
+                               ath10k_warn("htt rx msdu_chaining is true\n");
                                ath10k_htt_rx_free_msdu_chain(msdu_head);
                                continue;
                        }
@@ -975,6 +975,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                        info.skb     = msdu_head;
                        info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
                        info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head);
+
+                       if (info.fcs_err)
+                               ath10k_dbg(ATH10K_DBG_HTT,
+                                          "htt rx has FCS err\n");
+
+                       if (info.mic_err)
+                               ath10k_dbg(ATH10K_DBG_HTT,
+                                          "htt rx has MIC err\n");
+
                        info.signal  = ATH10K_DEFAULT_NOISE_FLOOR;
                        info.signal += rx->ppdu.combined_rssi;
 
@@ -1095,7 +1104,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 
        skb_trim(info.skb, info.skb->len - trim);
 
-       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt frag mpdu: ",
+       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
                        info.skb->data, info.skb->len);
        ath10k_process_rx(htt->ar, &info);
 
@@ -1116,7 +1125,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
        if (!IS_ALIGNED((unsigned long)skb->data, 4))
                ath10k_warn("unaligned htt message, expect trouble\n");
 
-       ath10k_dbg(ATH10K_DBG_HTT, "HTT RX, msg_type: 0x%0X\n",
+       ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
                   resp->hdr.msg_type);
        switch (resp->hdr.msg_type) {
        case HTT_T2H_MSG_TYPE_VERSION_CONF: {
index f1d36d2d27235aeec979fed652d2925ec6e94513..acaa046dc93b3c37a738eb015a00104ec58eaee7 100644 (file)
@@ -460,9 +460,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
                                           DMA_TO_DEVICE);
        }
 
-       ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n",
+       ath10k_dbg(ATH10K_DBG_HTT, "tx-msdu 0x%llx\n",
                   (unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
-       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ",
+       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "tx-msdu: ",
                        msdu->data, msdu->len);
 
        skb_put(txdesc, desc_len);
index f1505a25d8109b3cf1a315c548aad9348ea0e441..35fc44e281f57968171283d7d336cce5b20eddac 100644 (file)
@@ -205,8 +205,11 @@ enum ath10k_mcast2ucast_mode {
 #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS     0x0006c000
 #define PCIE_LOCAL_BASE_ADDRESS                        0x00080000
 
+#define SOC_RESET_CONTROL_ADDRESS              0x00000000
 #define SOC_RESET_CONTROL_OFFSET               0x00000000
 #define SOC_RESET_CONTROL_SI0_RST_MASK         0x00000001
+#define SOC_RESET_CONTROL_CE_RST_MASK          0x00040000
+#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK    0x00000040
 #define SOC_CPU_CLOCK_OFFSET                   0x00000020
 #define SOC_CPU_CLOCK_STANDARD_LSB             0
 #define SOC_CPU_CLOCK_STANDARD_MASK            0x00000003
@@ -216,6 +219,8 @@ enum ath10k_mcast2ucast_mode {
 #define SOC_LPO_CAL_OFFSET                     0x000000e0
 #define SOC_LPO_CAL_ENABLE_LSB                 20
 #define SOC_LPO_CAL_ENABLE_MASK                        0x00100000
+#define SOC_LF_TIMER_CONTROL0_ADDRESS          0x00000050
+#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK      0x00000004
 
 #define SOC_CHIP_ID_ADDRESS                    0x000000ec
 #define SOC_CHIP_ID_REV_LSB                    8
@@ -273,6 +278,7 @@ enum ath10k_mcast2ucast_mode {
 #define PCIE_INTR_CAUSE_ADDRESS                        0x000c
 #define PCIE_INTR_CLR_ADDRESS                  0x0014
 #define SCRATCH_3_ADDRESS                      0x0030
+#define CPU_INTR_ADDRESS                       0x0010
 
 /* Firmware indications to the Host via SCRATCH_3 register. */
 #define FW_INDICATOR_ADDRESS   (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS)
index 776e364eadcd76c82ed37a64e20601f5bb1926ab..e17f5d732b5abf099eeaa590bca0be746aed073e 100644 (file)
@@ -339,6 +339,50 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
        return 0;
 }
 
+static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+       u32 param;
+       int ret;
+
+       param = ar->wmi.pdev_param->sta_kickout_th;
+       ret = ath10k_wmi_pdev_set_param(ar, param,
+                                       ATH10K_KICKOUT_THRESHOLD);
+       if (ret) {
+               ath10k_warn("Failed to set kickout threshold: %d\n", ret);
+               return ret;
+       }
+
+       param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs;
+       ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
+                                       ATH10K_KEEPALIVE_MIN_IDLE);
+       if (ret) {
+               ath10k_warn("Failed to set keepalive minimum idle time : %d\n",
+                           ret);
+               return ret;
+       }
+
+       param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs;
+       ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
+                                       ATH10K_KEEPALIVE_MAX_IDLE);
+       if (ret) {
+               ath10k_warn("Failed to set keepalive maximum idle time: %d\n",
+                           ret);
+               return ret;
+       }
+
+       param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs;
+       ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
+                                       ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
+       if (ret) {
+               ath10k_warn("Failed to set keepalive maximum unresponsive time: %d\n",
+                           ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int  ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
 {
        struct ath10k *ar = arvif->ar;
@@ -444,8 +488,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
 static int ath10k_vdev_start(struct ath10k_vif *arvif)
 {
        struct ath10k *ar = arvif->ar;
-       struct ieee80211_conf *conf = &ar->hw->conf;
-       struct ieee80211_channel *channel = conf->chandef.chan;
+       struct cfg80211_chan_def *chandef = &ar->chandef;
        struct wmi_vdev_start_request_arg arg = {};
        int ret = 0;
 
@@ -457,16 +500,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
        arg.dtim_period = arvif->dtim_period;
        arg.bcn_intval = arvif->beacon_interval;
 
-       arg.channel.freq = channel->center_freq;
-
-       arg.channel.band_center_freq1 = conf->chandef.center_freq1;
-
-       arg.channel.mode = chan_to_phymode(&conf->chandef);
+       arg.channel.freq = chandef->chan->center_freq;
+       arg.channel.band_center_freq1 = chandef->center_freq1;
+       arg.channel.mode = chan_to_phymode(chandef);
 
        arg.channel.min_power = 0;
-       arg.channel.max_power = channel->max_power * 2;
-       arg.channel.max_reg_power = channel->max_reg_power * 2;
-       arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
+       arg.channel.max_power = chandef->chan->max_power * 2;
+       arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
+       arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
 
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
                arg.ssid = arvif->u.ap.ssid;
@@ -475,7 +516,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
 
                /* For now allow DFS for AP mode */
                arg.channel.chan_radar =
-                       !!(channel->flags & IEEE80211_CHAN_RADAR);
+                       !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
        } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
                arg.ssid = arvif->vif->bss_conf.ssid;
                arg.ssid_len = arvif->vif->bss_conf.ssid_len;
@@ -527,7 +568,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
 
 static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 {
-       struct ieee80211_channel *channel = ar->hw->conf.chandef.chan;
+       struct cfg80211_chan_def *chandef = &ar->chandef;
+       struct ieee80211_channel *channel = chandef->chan;
        struct wmi_vdev_start_request_arg arg = {};
        int ret = 0;
 
@@ -540,11 +582,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 
        arg.vdev_id = vdev_id;
        arg.channel.freq = channel->center_freq;
-       arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1;
+       arg.channel.band_center_freq1 = chandef->center_freq1;
 
        /* TODO setup this dynamically, what in case we
           don't have any vifs? */
-       arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef);
+       arg.channel.mode = chan_to_phymode(chandef);
        arg.channel.chan_radar =
                        !!(channel->flags & IEEE80211_CHAN_RADAR);
 
@@ -791,6 +833,20 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
 
        if (!info->enable_beacon) {
                ath10k_vdev_stop(arvif);
+
+               arvif->is_started = false;
+               arvif->is_up = false;
+
+               spin_lock_bh(&arvif->ar->data_lock);
+               if (arvif->beacon) {
+                       ath10k_skb_unmap(arvif->ar->dev, arvif->beacon);
+                       dev_kfree_skb_any(arvif->beacon);
+
+                       arvif->beacon = NULL;
+                       arvif->beacon_sent = false;
+               }
+               spin_unlock_bh(&arvif->ar->data_lock);
+
                return;
        }
 
@@ -800,12 +856,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
        if (ret)
                return;
 
-       ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid);
+       arvif->aid = 0;
+       memcpy(arvif->bssid, info->bssid, ETH_ALEN);
+
+       ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+                                arvif->bssid);
        if (ret) {
                ath10k_warn("Failed to bring up VDEV: %d\n",
                            arvif->vdev_id);
+               ath10k_vdev_stop(arvif);
                return;
        }
+
+       arvif->is_started = true;
+       arvif->is_up = true;
+
        ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
 }
 
@@ -824,18 +889,18 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
                        ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n",
                                    self_peer, arvif->vdev_id, ret);
 
-               if (is_zero_ether_addr(arvif->u.ibss.bssid))
+               if (is_zero_ether_addr(arvif->bssid))
                        return;
 
                ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
-                                        arvif->u.ibss.bssid);
+                                        arvif->bssid);
                if (ret) {
                        ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n",
-                                   arvif->u.ibss.bssid, arvif->vdev_id, ret);
+                                   arvif->bssid, arvif->vdev_id, ret);
                        return;
                }
 
-               memset(arvif->u.ibss.bssid, 0, ETH_ALEN);
+               memset(arvif->bssid, 0, ETH_ALEN);
 
                return;
        }
@@ -1017,7 +1082,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
                                   struct wmi_peer_assoc_complete_arg *arg)
 {
        const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-       int smps;
        int i, n;
 
        lockdep_assert_held(&ar->conf_mutex);
@@ -1063,17 +1127,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
                arg->peer_flags |= WMI_PEER_STBC;
        }
 
-       smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
-       smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
-
-       if (smps == WLAN_HT_CAP_SM_PS_STATIC) {
-               arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
-               arg->peer_flags |= WMI_PEER_STATIC_MIMOPS;
-       } else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) {
-               arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
-               arg->peer_flags |= WMI_PEER_DYN_MIMOPS;
-       }
-
        if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
                arg->peer_rate_caps |= WMI_RC_TS_FLAG;
        else if (ht_cap->mcs.rx_mask[1])
@@ -1083,8 +1136,23 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
                if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8))
                        arg->peer_ht_rates.rates[n++] = i;
 
-       arg->peer_ht_rates.num_rates = n;
-       arg->peer_num_spatial_streams = max((n+7) / 8, 1);
+       /*
+        * This is a workaround for HT-enabled STAs which break the spec
+        * and have no HT capabilities RX mask (no HT RX MCS map).
+        *
+        * As per spec, in section 20.3.5 Modulation and coding scheme (MCS),
+        * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs.
+        *
+        * Firmware asserts if such situation occurs.
+        */
+       if (n == 0) {
+               arg->peer_ht_rates.num_rates = 8;
+               for (i = 0; i < arg->peer_ht_rates.num_rates; i++)
+                       arg->peer_ht_rates.rates[i] = i;
+       } else {
+               arg->peer_ht_rates.num_rates = n;
+               arg->peer_num_spatial_streams = sta->rx_nss;
+       }
 
        ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
                   arg->addr,
@@ -1092,27 +1160,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
                   arg->peer_num_spatial_streams);
 }
 
-static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
-                                      struct ath10k_vif *arvif,
-                                      struct ieee80211_sta *sta,
-                                      struct ieee80211_bss_conf *bss_conf,
-                                      struct wmi_peer_assoc_complete_arg *arg)
+static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
+                                   struct ath10k_vif *arvif,
+                                   struct ieee80211_sta *sta)
 {
        u32 uapsd = 0;
        u32 max_sp = 0;
+       int ret = 0;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       if (sta->wme)
-               arg->peer_flags |= WMI_PEER_QOS;
-
        if (sta->wme && sta->uapsd_queues) {
                ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
                           sta->uapsd_queues, sta->max_sp);
 
-               arg->peer_flags |= WMI_PEER_APSD;
-               arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
-
                if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
                        uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
                                 WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
@@ -1130,35 +1191,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
                if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
                        max_sp = sta->max_sp;
 
-               ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
-                                          sta->addr,
-                                          WMI_AP_PS_PEER_PARAM_UAPSD,
-                                          uapsd);
+               ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
+                                                sta->addr,
+                                                WMI_AP_PS_PEER_PARAM_UAPSD,
+                                                uapsd);
+               if (ret) {
+                       ath10k_warn("failed to set ap ps peer param uapsd: %d\n",
+                                   ret);
+                       return ret;
+               }
 
-               ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
-                                          sta->addr,
-                                          WMI_AP_PS_PEER_PARAM_MAX_SP,
-                                          max_sp);
+               ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
+                                                sta->addr,
+                                                WMI_AP_PS_PEER_PARAM_MAX_SP,
+                                                max_sp);
+               if (ret) {
+                       ath10k_warn("failed to set ap ps peer param max sp: %d\n",
+                                   ret);
+                       return ret;
+               }
 
                /* TODO setup this based on STA listen interval and
                   beacon interval. Currently we don't know
                   sta->listen_interval - mac80211 patch required.
                   Currently use 10 seconds */
-               ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
-                                          sta->addr,
-                                          WMI_AP_PS_PEER_PARAM_AGEOUT_TIME,
-                                          10);
+               ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
+                                       WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
+               if (ret) {
+                       ath10k_warn("failed to set ap ps peer param ageout time: %d\n",
+                                   ret);
+                       return ret;
+               }
        }
-}
 
-static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar,
-                                       struct ath10k_vif *arvif,
-                                       struct ieee80211_sta *sta,
-                                       struct ieee80211_bss_conf *bss_conf,
-                                       struct wmi_peer_assoc_complete_arg *arg)
-{
-       if (bss_conf->qos)
-               arg->peer_flags |= WMI_PEER_QOS;
+       return 0;
 }
 
 static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
@@ -1211,10 +1277,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
 {
        switch (arvif->vdev_type) {
        case WMI_VDEV_TYPE_AP:
-               ath10k_peer_assoc_h_qos_ap(ar, arvif, sta, bss_conf, arg);
+               if (sta->wme)
+                       arg->peer_flags |= WMI_PEER_QOS;
+
+               if (sta->wme && sta->uapsd_queues) {
+                       arg->peer_flags |= WMI_PEER_APSD;
+                       arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
+               }
                break;
        case WMI_VDEV_TYPE_STA:
-               ath10k_peer_assoc_h_qos_sta(ar, arvif, sta, bss_conf, arg);
+               if (bss_conf->qos)
+                       arg->peer_flags |= WMI_PEER_QOS;
                break;
        default:
                break;
@@ -1293,6 +1366,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
        return 0;
 }
 
+static const u32 ath10k_smps_map[] = {
+       [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC,
+       [WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC,
+       [WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE,
+       [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
+};
+
+static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif,
+                                 const u8 *addr,
+                                 const struct ieee80211_sta_ht_cap *ht_cap)
+{
+       int smps;
+
+       if (!ht_cap->ht_supported)
+               return 0;
+
+       smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
+       smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+       if (smps >= ARRAY_SIZE(ath10k_smps_map))
+               return -EINVAL;
+
+       return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr,
+                                        WMI_PEER_SMPS_STATE,
+                                        ath10k_smps_map[smps]);
+}
+
 /* can be called only in mac80211 callbacks due to `key_count` usage */
 static void ath10k_bss_assoc(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif,
@@ -1300,6 +1400,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 {
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+       struct ieee80211_sta_ht_cap ht_cap;
        struct wmi_peer_assoc_complete_arg peer_arg;
        struct ieee80211_sta *ap_sta;
        int ret;
@@ -1316,6 +1417,10 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
                return;
        }
 
+       /* ap_sta must be accessed only within rcu section which must be left
+        * before calling ath10k_setup_peer_smps() which might sleep. */
+       ht_cap = ap_sta->ht_cap;
+
        ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
                                        bss_conf, &peer_arg);
        if (ret) {
@@ -1334,15 +1439,27 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
                return;
        }
 
+       ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
+       if (ret) {
+               ath10k_warn("failed to setup peer SMPS: %d\n", ret);
+               return;
+       }
+
        ath10k_dbg(ATH10K_DBG_MAC,
                   "mac vdev %d up (associated) bssid %pM aid %d\n",
                   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
 
-       ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid,
-                                bss_conf->bssid);
-       if (ret)
+       arvif->aid = bss_conf->aid;
+       memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
+
+       ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
+       if (ret) {
                ath10k_warn("VDEV: %d up failed: ret %d\n",
                            arvif->vdev_id, ret);
+               return;
+       }
+
+       arvif->is_up = true;
 }
 
 /*
@@ -1382,6 +1499,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
        ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
 
        arvif->def_wep_key_idx = 0;
+
+       arvif->is_started = false;
+       arvif->is_up = false;
 }
 
 static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
@@ -1406,12 +1526,25 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
                return ret;
        }
 
+       ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
+       if (ret) {
+               ath10k_warn("failed to setup peer SMPS: %d\n", ret);
+               return ret;
+       }
+
        ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
        if (ret) {
                ath10k_warn("could not install peer wep keys (%d)\n", ret);
                return ret;
        }
 
+       ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
+       if (ret) {
+               ath10k_warn("could not set qos params for STA %pM, %d\n",
+                           sta->addr, ret);
+               return ret;
+       }
+
        return ret;
 }
 
@@ -1547,9 +1680,9 @@ static void ath10k_regd_update(struct ath10k *ar)
        /* Target allows setting up per-band regdomain but ath_common provides
         * a combined one only */
        ret = ath10k_wmi_pdev_set_regdomain(ar,
-                                           regpair->regDmnEnum,
-                                           regpair->regDmnEnum, /* 2ghz */
-                                           regpair->regDmnEnum, /* 5ghz */
+                                           regpair->reg_domain,
+                                           regpair->reg_domain, /* 2ghz */
+                                           regpair->reg_domain, /* 5ghz */
                                            regpair->reg_2ghz_ctl,
                                            regpair->reg_5ghz_ctl);
        if (ret)
@@ -2100,11 +2233,29 @@ static int ath10k_start(struct ieee80211_hw *hw)
                ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
                            ret);
 
+       /*
+        * By default FW set ARP frames ac to voice (6). In that case ARP
+        * exchange is not working properly for UAPSD enabled AP. ARP requests
+        * which arrives with access category 0 are processed by network stack
+        * and send back with access category 0, but FW changes access category
+        * to 6. Set ARP frames access category to best effort (0) solves
+        * this problem.
+        */
+
+       ret = ath10k_wmi_pdev_set_param(ar,
+                                       ar->wmi.pdev_param->arp_ac_override, 0);
+       if (ret) {
+               ath10k_warn("could not set arp ac override parameter: %d\n",
+                           ret);
+               goto exit;
+       }
+
        ath10k_regd_update(ar);
+       ret = 0;
 
 exit:
        mutex_unlock(&ar->conf_mutex);
-       return 0;
+       return ret;
 }
 
 static void ath10k_stop(struct ieee80211_hw *hw)
@@ -2145,6 +2296,98 @@ static int ath10k_config_ps(struct ath10k *ar)
        return ret;
 }
 
+static const char *chandef_get_width(enum nl80211_chan_width width)
+{
+       switch (width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               return "20 (noht)";
+       case NL80211_CHAN_WIDTH_20:
+               return "20";
+       case NL80211_CHAN_WIDTH_40:
+               return "40";
+       case NL80211_CHAN_WIDTH_80:
+               return "80";
+       case NL80211_CHAN_WIDTH_80P80:
+               return "80+80";
+       case NL80211_CHAN_WIDTH_160:
+               return "160";
+       case NL80211_CHAN_WIDTH_5:
+               return "5";
+       case NL80211_CHAN_WIDTH_10:
+               return "10";
+       }
+       return "?";
+}
+
+static void ath10k_config_chan(struct ath10k *ar)
+{
+       struct ath10k_vif *arvif;
+       bool monitor_was_enabled;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ath10k_dbg(ATH10K_DBG_MAC,
+                  "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
+                  ar->chandef.chan->center_freq,
+                  ar->chandef.center_freq1,
+                  ar->chandef.center_freq2,
+                  chandef_get_width(ar->chandef.width));
+
+       /* First stop monitor interface. Some FW versions crash if there's a
+        * lone monitor interface. */
+       monitor_was_enabled = ar->monitor_enabled;
+
+       if (ar->monitor_enabled)
+               ath10k_monitor_stop(ar);
+
+       list_for_each_entry(arvif, &ar->arvifs, list) {
+               if (!arvif->is_started)
+                       continue;
+
+               if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
+                       continue;
+
+               ret = ath10k_vdev_stop(arvif);
+               if (ret) {
+                       ath10k_warn("could not stop vdev %d (%d)\n",
+                                   arvif->vdev_id, ret);
+                       continue;
+               }
+       }
+
+       /* all vdevs are now stopped - now attempt to restart them */
+
+       list_for_each_entry(arvif, &ar->arvifs, list) {
+               if (!arvif->is_started)
+                       continue;
+
+               if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
+                       continue;
+
+               ret = ath10k_vdev_start(arvif);
+               if (ret) {
+                       ath10k_warn("could not start vdev %d (%d)\n",
+                                   arvif->vdev_id, ret);
+                       continue;
+               }
+
+               if (!arvif->is_up)
+                       continue;
+
+               ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+                                        arvif->bssid);
+               if (ret) {
+                       ath10k_warn("could not bring vdev up %d (%d)\n",
+                                   arvif->vdev_id, ret);
+                       continue;
+               }
+       }
+
+       if (monitor_was_enabled)
+               ath10k_monitor_start(ar, ar->monitor_vdev_id);
+}
+
 static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct ath10k *ar = hw->priv;
@@ -2165,6 +2408,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
                spin_unlock_bh(&ar->data_lock);
 
                ath10k_config_radar_detection(ar);
+
+               if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) {
+                       ar->chandef = conf->chandef;
+                       ath10k_config_chan(ar);
+               }
        }
 
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -2214,7 +2462,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        enum wmi_sta_powersave_param param;
        int ret = 0;
-       u32 value, param_id;
+       u32 value;
        int bit;
        u32 vdev_param;
 
@@ -2307,12 +2555,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                        goto err_vdev_delete;
                }
 
-               param_id = ar->wmi.pdev_param->sta_kickout_th;
-
-               /* Disable STA KICKOUT functionality in FW */
-               ret = ath10k_wmi_pdev_set_param(ar, param_id, 0);
-               if (ret)
-                       ath10k_warn("Failed to disable STA KICKOUT\n");
+               ret = ath10k_mac_set_kickout(arvif);
+               if (ret) {
+                       ath10k_warn("Failed to set kickout parameters: %d\n",
+                                   ret);
+                       goto err_peer_delete;
+               }
        }
 
        if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
@@ -2559,15 +2807,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                                 * this is never erased as we it for crypto key
                                 * clearing; this is FW requirement
                                 */
-                               memcpy(arvif->u.sta.bssid, info->bssid,
-                                      ETH_ALEN);
+                               memcpy(arvif->bssid, info->bssid, ETH_ALEN);
 
                                ath10k_dbg(ATH10K_DBG_MAC,
                                           "mac vdev %d start %pM\n",
                                           arvif->vdev_id, info->bssid);
 
-                               /* FIXME: check return value */
                                ret = ath10k_vdev_start(arvif);
+                               if (ret) {
+                                       ath10k_warn("failed to start vdev: %d\n",
+                                                   ret);
+                                       goto exit;
+                               }
+
+                               arvif->is_started = true;
                        }
 
                        /*
@@ -2576,7 +2829,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                         * IBSS in order to remove BSSID peer.
                         */
                        if (vif->type == NL80211_IFTYPE_ADHOC)
-                               memcpy(arvif->u.ibss.bssid, info->bssid,
+                               memcpy(arvif->bssid, info->bssid,
                                       ETH_ALEN);
                }
        }
@@ -2645,6 +2898,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                        ath10k_bss_assoc(hw, vif, info);
        }
 
+exit:
        mutex_unlock(&ar->conf_mutex);
 }
 
@@ -2850,6 +3104,69 @@ exit:
        return ret;
 }
 
+static void ath10k_sta_rc_update_wk(struct work_struct *wk)
+{
+       struct ath10k *ar;
+       struct ath10k_vif *arvif;
+       struct ath10k_sta *arsta;
+       struct ieee80211_sta *sta;
+       u32 changed, bw, nss, smps;
+       int err;
+
+       arsta = container_of(wk, struct ath10k_sta, update_wk);
+       sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
+       arvif = arsta->arvif;
+       ar = arvif->ar;
+
+       spin_lock_bh(&ar->data_lock);
+
+       changed = arsta->changed;
+       arsta->changed = 0;
+
+       bw = arsta->bw;
+       nss = arsta->nss;
+       smps = arsta->smps;
+
+       spin_unlock_bh(&ar->data_lock);
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (changed & IEEE80211_RC_BW_CHANGED) {
+               ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
+                          sta->addr, bw);
+
+               err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+                                               WMI_PEER_CHAN_WIDTH, bw);
+               if (err)
+                       ath10k_warn("failed to update STA %pM peer bw %d: %d\n",
+                                   sta->addr, bw, err);
+       }
+
+       if (changed & IEEE80211_RC_NSS_CHANGED) {
+               ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
+                          sta->addr, nss);
+
+               err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+                                               WMI_PEER_NSS, nss);
+               if (err)
+                       ath10k_warn("failed to update STA %pM nss %d: %d\n",
+                                   sta->addr, nss, err);
+       }
+
+       if (changed & IEEE80211_RC_SMPS_CHANGED) {
+               ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
+                          sta->addr, smps);
+
+               err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+                                               WMI_PEER_SMPS_STATE, smps);
+               if (err)
+                       ath10k_warn("failed to update STA %pM smps %d: %d\n",
+                                   sta->addr, smps, err);
+       }
+
+       mutex_unlock(&ar->conf_mutex);
+}
+
 static int ath10k_sta_state(struct ieee80211_hw *hw,
                            struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta,
@@ -2858,9 +3175,15 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 {
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+       struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
        int max_num_peers;
        int ret = 0;
 
+       /* cancel must be done outside the mutex to avoid deadlock */
+       if ((old_state == IEEE80211_STA_NONE &&
+            new_state == IEEE80211_STA_NOTEXIST))
+               cancel_work_sync(&arsta->update_wk);
+
        mutex_lock(&ar->conf_mutex);
 
        if (old_state == IEEE80211_STA_NOTEXIST &&
@@ -2885,6 +3208,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                           "mac vdev %d peer create %pM (new sta) num_peers %d\n",
                           arvif->vdev_id, sta->addr, ar->num_peers);
 
+               memset(arsta, 0, sizeof(*arsta));
+               arsta->arvif = arvif;
+               INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);
+
                ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
                if (ret)
                        ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n",
@@ -3234,23 +3561,14 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
        struct ath10k *ar = hw->priv;
        int ret;
 
-       ar->is_target_paused = false;
+       mutex_lock(&ar->conf_mutex);
 
-       ret = ath10k_wmi_pdev_suspend_target(ar);
+       ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND);
        if (ret) {
-               ath10k_warn("could not suspend target (%d)\n", ret);
-               return 1;
-       }
-
-       ret = wait_event_interruptible_timeout(ar->event_queue,
-                                              ar->is_target_paused == true,
-                                              1 * HZ);
-       if (ret < 0) {
-               ath10k_warn("suspend interrupted (%d)\n", ret);
-               goto resume;
-       } else if (ret == 0) {
-               ath10k_warn("suspend timed out - target pause event never came\n");
-               goto resume;
+               if (ret == -ETIMEDOUT)
+                       goto resume;
+               ret = 1;
+               goto exit;
        }
 
        ret = ath10k_hif_suspend(ar);
@@ -3259,12 +3577,17 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
                goto resume;
        }
 
-       return 0;
+       ret = 0;
+       goto exit;
 resume:
        ret = ath10k_wmi_pdev_resume_target(ar);
        if (ret)
                ath10k_warn("could not resume target (%d)\n", ret);
-       return 1;
+
+       ret = 1;
+exit:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
 }
 
 static int ath10k_resume(struct ieee80211_hw *hw)
@@ -3272,19 +3595,26 @@ static int ath10k_resume(struct ieee80211_hw *hw)
        struct ath10k *ar = hw->priv;
        int ret;
 
+       mutex_lock(&ar->conf_mutex);
+
        ret = ath10k_hif_resume(ar);
        if (ret) {
                ath10k_warn("could not resume hif (%d)\n", ret);
-               return 1;
+               ret = 1;
+               goto exit;
        }
 
        ret = ath10k_wmi_pdev_resume_target(ar);
        if (ret) {
                ath10k_warn("could not resume target (%d)\n", ret);
-               return 1;
+               ret = 1;
+               goto exit;
        }
 
-       return 0;
+       ret = 0;
+exit:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
 }
 #endif
 
@@ -3640,6 +3970,96 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
        return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss);
 }
 
+static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw,
+                                        struct ieee80211_vif *vif,
+                                        struct cfg80211_chan_def *chandef)
+{
+       /* there's no need to do anything here. vif->csa_active is enough */
+       return;
+}
+
+static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_sta *sta,
+                                u32 changed)
+{
+       struct ath10k *ar = hw->priv;
+       struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+       u32 bw, smps;
+
+       spin_lock_bh(&ar->data_lock);
+
+       ath10k_dbg(ATH10K_DBG_MAC,
+                  "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
+                  sta->addr, changed, sta->bandwidth, sta->rx_nss,
+                  sta->smps_mode);
+
+       if (changed & IEEE80211_RC_BW_CHANGED) {
+               bw = WMI_PEER_CHWIDTH_20MHZ;
+
+               switch (sta->bandwidth) {
+               case IEEE80211_STA_RX_BW_20:
+                       bw = WMI_PEER_CHWIDTH_20MHZ;
+                       break;
+               case IEEE80211_STA_RX_BW_40:
+                       bw = WMI_PEER_CHWIDTH_40MHZ;
+                       break;
+               case IEEE80211_STA_RX_BW_80:
+                       bw = WMI_PEER_CHWIDTH_80MHZ;
+                       break;
+               case IEEE80211_STA_RX_BW_160:
+                       ath10k_warn("mac sta rc update for %pM: invalid bw %d\n",
+                                   sta->addr, sta->bandwidth);
+                       bw = WMI_PEER_CHWIDTH_20MHZ;
+                       break;
+               }
+
+               arsta->bw = bw;
+       }
+
+       if (changed & IEEE80211_RC_NSS_CHANGED)
+               arsta->nss = sta->rx_nss;
+
+       if (changed & IEEE80211_RC_SMPS_CHANGED) {
+               smps = WMI_PEER_SMPS_PS_NONE;
+
+               switch (sta->smps_mode) {
+               case IEEE80211_SMPS_AUTOMATIC:
+               case IEEE80211_SMPS_OFF:
+                       smps = WMI_PEER_SMPS_PS_NONE;
+                       break;
+               case IEEE80211_SMPS_STATIC:
+                       smps = WMI_PEER_SMPS_STATIC;
+                       break;
+               case IEEE80211_SMPS_DYNAMIC:
+                       smps = WMI_PEER_SMPS_DYNAMIC;
+                       break;
+               case IEEE80211_SMPS_NUM_MODES:
+                       ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n",
+                                   sta->addr, sta->smps_mode);
+                       smps = WMI_PEER_SMPS_PS_NONE;
+                       break;
+               }
+
+               arsta->smps = smps;
+       }
+
+       if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+               /* FIXME: Not implemented. Probably the only way to do it would
+                * be to re-assoc the peer. */
+               changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED;
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "mac sta rc update for %pM: changing supported rates not implemented\n",
+                          sta->addr);
+       }
+
+       arsta->changed |= changed;
+
+       spin_unlock_bh(&ar->data_lock);
+
+       ieee80211_queue_work(hw, &arsta->update_wk);
+}
+
 static const struct ieee80211_ops ath10k_ops = {
        .tx                             = ath10k_tx,
        .start                          = ath10k_start,
@@ -3663,6 +4083,8 @@ static const struct ieee80211_ops ath10k_ops = {
        .restart_complete               = ath10k_restart_complete,
        .get_survey                     = ath10k_get_survey,
        .set_bitrate_mask               = ath10k_set_bitrate_mask,
+       .channel_switch_beacon          = ath10k_channel_switch_beacon,
+       .sta_rc_update                  = ath10k_sta_rc_update,
 #ifdef CONFIG_PM
        .suspend                        = ath10k_suspend,
        .resume                         = ath10k_resume,
@@ -4038,10 +4460,12 @@ int ath10k_mac_register(struct ath10k *ar)
        ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
 
        ar->hw->vif_data_size = sizeof(struct ath10k_vif);
+       ar->hw->sta_data_size = sizeof(struct ath10k_sta);
 
        ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
 
        ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+       ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
        ar->hw->wiphy->max_remain_on_channel_duration = 5000;
 
        ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
index 29fd197d1fd8b3b7e8da66b212d0452c4e3ec3de..34f09106f423f1bf45654468bdcdefafda81d97a 100644 (file)
@@ -64,7 +64,8 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
                                             int num);
 static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
 static void ath10k_pci_stop_ce(struct ath10k *ar);
-static int ath10k_pci_device_reset(struct ath10k *ar);
+static int ath10k_pci_cold_reset(struct ath10k *ar);
+static int ath10k_pci_warm_reset(struct ath10k *ar);
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
 static int ath10k_pci_init_irq(struct ath10k *ar);
 static int ath10k_pci_deinit_irq(struct ath10k *ar);
@@ -833,9 +834,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
        ath10k_err("firmware crashed!\n");
        ath10k_err("hardware name %s version 0x%x\n",
                   ar->hw_params.name, ar->target_version);
-       ath10k_err("firmware version: %u.%u.%u.%u\n", ar->fw_version_major,
-                  ar->fw_version_minor, ar->fw_version_release,
-                  ar->fw_version_build);
+       ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
 
        host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
        ret = ath10k_pci_diag_read_mem(ar, host_addr,
@@ -1502,7 +1501,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
         * configuration during init. If ringbuffers are freed and the device
         * were to access them this could lead to memory corruption on the
         * host. */
-       ath10k_pci_device_reset(ar);
+       ath10k_pci_warm_reset(ar);
 
        ar_pci->started = 0;
 }
@@ -1993,7 +1992,94 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
        ath10k_pci_sleep(ar);
 }
 
-static int ath10k_pci_hif_power_up(struct ath10k *ar)
+static int ath10k_pci_warm_reset(struct ath10k *ar)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       int ret = 0;
+       u32 val;
+
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot performing warm chip reset\n");
+
+       ret = ath10k_do_pci_wake(ar);
+       if (ret) {
+               ath10k_err("failed to wake up target: %d\n", ret);
+               return ret;
+       }
+
+       /* debug */
+       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+                               PCIE_INTR_CAUSE_ADDRESS);
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+
+       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+                               CPU_INTR_ADDRESS);
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+                  val);
+
+       /* disable pending irqs */
+       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+                          PCIE_INTR_ENABLE_ADDRESS, 0);
+
+       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+                          PCIE_INTR_CLR_ADDRESS, ~0);
+
+       msleep(100);
+
+       /* clear fw indicator */
+       ath10k_pci_write32(ar, ar_pci->fw_indicator_address, 0);
+
+       /* clear target LF timer interrupts */
+       val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+                               SOC_LF_TIMER_CONTROL0_ADDRESS);
+       ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS +
+                          SOC_LF_TIMER_CONTROL0_ADDRESS,
+                          val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK);
+
+       /* reset CE */
+       val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+                               SOC_RESET_CONTROL_ADDRESS);
+       ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
+                          val | SOC_RESET_CONTROL_CE_RST_MASK);
+       val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+                               SOC_RESET_CONTROL_ADDRESS);
+       msleep(10);
+
+       /* unreset CE */
+       ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
+                          val & ~SOC_RESET_CONTROL_CE_RST_MASK);
+       val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+                               SOC_RESET_CONTROL_ADDRESS);
+       msleep(10);
+
+       /* debug */
+       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+                               PCIE_INTR_CAUSE_ADDRESS);
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+
+       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+                               CPU_INTR_ADDRESS);
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+                  val);
+
+       /* CPU warm reset */
+       val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+                               SOC_RESET_CONTROL_ADDRESS);
+       ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
+                          val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK);
+
+       val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
+                               SOC_RESET_CONTROL_ADDRESS);
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val);
+
+       msleep(100);
+
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n");
+
+       ath10k_do_pci_sleep(ar);
+       return ret;
+}
+
+static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        const char *irq_mode;
@@ -2009,7 +2095,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
         * is in an unexpected state. We try to catch that here in order to
         * reset the Target and retry the probe.
         */
-       ret = ath10k_pci_device_reset(ar);
+       if (cold_reset)
+               ret = ath10k_pci_cold_reset(ar);
+       else
+               ret = ath10k_pci_warm_reset(ar);
+
        if (ret) {
                ath10k_err("failed to reset target: %d\n", ret);
                goto err;
@@ -2079,7 +2169,7 @@ err_deinit_irq:
        ath10k_pci_deinit_irq(ar);
 err_ce:
        ath10k_pci_ce_deinit(ar);
-       ath10k_pci_device_reset(ar);
+       ath10k_pci_warm_reset(ar);
 err_ps:
        if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
                ath10k_do_pci_sleep(ar);
@@ -2087,6 +2177,34 @@ err:
        return ret;
 }
 
+static int ath10k_pci_hif_power_up(struct ath10k *ar)
+{
+       int ret;
+
+       /*
+        * Hardware CUS232 version 2 has some issues with cold reset and the
+        * preferred (and safer) way to perform a device reset is through a
+        * warm reset.
+        *
+        * Warm reset doesn't always work though (notably after a firmware
+        * crash) so fall back to cold reset if necessary.
+        */
+       ret = __ath10k_pci_hif_power_up(ar, false);
+       if (ret) {
+               ath10k_warn("failed to power up target using warm reset (%d), trying cold reset\n",
+                           ret);
+
+               ret = __ath10k_pci_hif_power_up(ar, true);
+               if (ret) {
+                       ath10k_err("failed to power up target using cold reset too (%d)\n",
+                                  ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static void ath10k_pci_hif_power_down(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -2094,7 +2212,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
        ath10k_pci_free_early_irq(ar);
        ath10k_pci_kill_tasklet(ar);
        ath10k_pci_deinit_irq(ar);
-       ath10k_pci_device_reset(ar);
+       ath10k_pci_warm_reset(ar);
 
        ath10k_pci_ce_deinit(ar);
        if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
@@ -2411,11 +2529,10 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
        /* Try MSI-X */
        if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
                ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
-               ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
-               if (ret == 0)
-                       return 0;
+               ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
+                                                        ar_pci->num_msi_intrs);
                if (ret > 0)
-                       pci_disable_msi(ar_pci->pdev);
+                       return 0;
 
                /* fall-through */
        }
@@ -2482,6 +2599,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
        case MSI_NUM_REQUEST:
                pci_disable_msi(ar_pci->pdev);
                return 0;
+       default:
+               pci_disable_msi(ar_pci->pdev);
        }
 
        ath10k_warn("unknown irq configuration upon deinit\n");
@@ -2523,7 +2642,7 @@ out:
        return ret;
 }
 
-static int ath10k_pci_device_reset(struct ath10k *ar)
+static int ath10k_pci_cold_reset(struct ath10k *ar)
 {
        int i, ret;
        u32 val;
index 27f20e0510f7a1dc0574d746f90e3bcaa624f99c..ec6f82521b0ea6eb69e255d1b97bb6f99bfb78d7 100644 (file)
@@ -259,7 +259,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
        status->freq = ch->center_freq;
 
        ath10k_dbg(ATH10K_DBG_DATA,
-                  "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u\n",
+                  "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i\n",
                   info->skb,
                   info->skb->len,
                   status->flag == 0 ? "legacy" : "",
@@ -271,7 +271,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
                   status->rate_idx,
                   status->vht_nss,
                   status->freq,
-                  status->band);
+                  status->band, status->flag, info->fcs_err);
        ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
                        info->skb->data, info->skb->len);
 
index 712a606a080a02617fe839737ce4c2f5084a5881..91e501b5499ef0497b3bb8b22e718c691d00f315 100644 (file)
@@ -213,7 +213,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
        .p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE,
        .p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE,
        .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
-       .ap_ps_peer_param_cmdid = WMI_CMD_UNSUPPORTED,
+       .ap_ps_peer_param_cmdid = WMI_10X_AP_PS_PEER_PARAM_CMDID,
        .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
        .peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID,
        .wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID,
@@ -420,7 +420,6 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = {
        .bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
        .pmf_qos = WMI_PDEV_PARAM_PMF_QOS,
        .arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
-       .arpdhcp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
        .dcs = WMI_PDEV_PARAM_DCS,
        .ani_enable = WMI_PDEV_PARAM_ANI_ENABLE,
        .ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD,
@@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
        .bcnflt_stats_update_period =
                                WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
        .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS,
-       .arp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
-       .arpdhcp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
+       .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
        .dcs = WMI_10X_PDEV_PARAM_DCS,
        .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE,
        .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD,
@@ -561,7 +559,6 @@ err_pull:
 
 static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
 {
-       struct wmi_bcn_tx_arg arg = {0};
        int ret;
 
        lockdep_assert_held(&arvif->ar->data_lock);
@@ -569,18 +566,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
        if (arvif->beacon == NULL)
                return;
 
-       arg.vdev_id = arvif->vdev_id;
-       arg.tx_rate = 0;
-       arg.tx_power = 0;
-       arg.bcn = arvif->beacon->data;
-       arg.bcn_len = arvif->beacon->len;
+       if (arvif->beacon_sent)
+               return;
 
-       ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg);
+       ret = ath10k_wmi_beacon_send_ref_nowait(arvif);
        if (ret)
                return;
 
-       dev_kfree_skb_any(arvif->beacon);
-       arvif->beacon = NULL;
+       /* We need to retain the arvif->beacon reference for DMA unmapping and
+        * freeing the skbuff later. */
+       arvif->beacon_sent = true;
 }
 
 static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
@@ -1116,7 +1111,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
 static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
                                              struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n");
+       struct wmi_peer_sta_kickout_event *ev;
+       struct ieee80211_sta *sta;
+
+       ev = (struct wmi_peer_sta_kickout_event *)skb->data;
+
+       ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
+                  ev->peer_macaddr.addr);
+
+       rcu_read_lock();
+
+       sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
+       if (!sta) {
+               ath10k_warn("Spurious quick kickout for STA %pM\n",
+                           ev->peer_macaddr.addr);
+               goto exit;
+       }
+
+       ieee80211_report_low_ack(sta, 10);
+
+exit:
+       rcu_read_unlock();
 }
 
 /*
@@ -1217,6 +1232,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
        tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);
        memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
 
+       if (tim->dtim_count == 0) {
+               ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true;
+
+               if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1)
+                       ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
+       }
+
        ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
                   tim->dtim_count, tim->dtim_period,
                   tim->bitmap_ctrl, pvm_len);
@@ -1385,6 +1407,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                        continue;
                }
 
+               /* There are no completions for beacons so wait for next SWBA
+                * before telling mac80211 to decrement CSA counter
+                *
+                * Once CSA counter is completed stop sending beacons until
+                * actual channel switch is done */
+               if (arvif->vif->csa_active &&
+                   ieee80211_csa_is_complete(arvif->vif)) {
+                       ieee80211_csa_finish(arvif->vif);
+                       continue;
+               }
+
                bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
                if (!bcn) {
                        ath10k_warn("could not get mac80211 beacon\n");
@@ -1396,13 +1429,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
 
                spin_lock_bh(&ar->data_lock);
+
                if (arvif->beacon) {
-                       ath10k_warn("SWBA overrun on vdev %d\n",
-                                   arvif->vdev_id);
+                       if (!arvif->beacon_sent)
+                               ath10k_warn("SWBA overrun on vdev %d\n",
+                                           arvif->vdev_id);
+
+                       ath10k_skb_unmap(ar->dev, arvif->beacon);
                        dev_kfree_skb_any(arvif->beacon);
                }
 
+               ath10k_skb_map(ar->dev, bcn);
+
                arvif->beacon = bcn;
+               arvif->beacon_sent = false;
 
                ath10k_wmi_tx_beacon_nowait(arvif);
                spin_unlock_bh(&ar->data_lock);
@@ -2031,11 +2071,11 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
        memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
 
        ath10k_dbg(ATH10K_DBG_WMI,
-                  "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n",
+                  "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
                   __le32_to_cpu(ev->sw_version),
                   __le32_to_cpu(ev->abi_version),
                   ev->mac_addr.addr,
-                  __le32_to_cpu(ev->status));
+                  __le32_to_cpu(ev->status), skb->len, sizeof(*ev));
 
        complete(&ar->wmi.unified_ready);
        return 0;
@@ -2403,7 +2443,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
                                   ar->wmi.cmd->pdev_set_channel_cmdid);
 }
 
-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar)
+int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
 {
        struct wmi_pdev_suspend_cmd *cmd;
        struct sk_buff *skb;
@@ -2413,7 +2453,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar)
                return -ENOMEM;
 
        cmd = (struct wmi_pdev_suspend_cmd *)skb->data;
-       cmd->suspend_opt = WMI_PDEV_SUSPEND;
+       cmd->suspend_opt = __cpu_to_le32(suspend_opt);
 
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
 }
@@ -3411,25 +3451,41 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
 }
 
-int ath10k_wmi_beacon_send_nowait(struct ath10k *ar,
-                                 const struct wmi_bcn_tx_arg *arg)
+/* This function assumes the beacon is already DMA mapped */
+int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
 {
-       struct wmi_bcn_tx_cmd *cmd;
+       struct wmi_bcn_tx_ref_cmd *cmd;
        struct sk_buff *skb;
+       struct sk_buff *beacon = arvif->beacon;
+       struct ath10k *ar = arvif->ar;
+       struct ieee80211_hdr *hdr;
        int ret;
+       u16 fc;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len);
+       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
-       cmd = (struct wmi_bcn_tx_cmd *)skb->data;
-       cmd->hdr.vdev_id  = __cpu_to_le32(arg->vdev_id);
-       cmd->hdr.tx_rate  = __cpu_to_le32(arg->tx_rate);
-       cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power);
-       cmd->hdr.bcn_len  = __cpu_to_le32(arg->bcn_len);
-       memcpy(cmd->bcn, arg->bcn, arg->bcn_len);
+       hdr = (struct ieee80211_hdr *)beacon->data;
+       fc = le16_to_cpu(hdr->frame_control);
+
+       cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data;
+       cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
+       cmd->data_len = __cpu_to_le32(beacon->len);
+       cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr);
+       cmd->msdu_id = 0;
+       cmd->frame_control = __cpu_to_le32(fc);
+       cmd->flags = 0;
+
+       if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
+               cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
+
+       if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab)
+               cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
+
+       ret = ath10k_wmi_cmd_send_nowait(ar, skb,
+                                        ar->wmi.cmd->pdev_send_bcn_cmdid);
 
-       ret = ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid);
        if (ret)
                dev_kfree_skb(skb);
 
index 4b5e7d3d32b62ff221992c6175db1d53f718b91e..4fcc96aa9513b89a45e11fd9c2d8da79414204c9 100644 (file)
@@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map {
        u32 bcnflt_stats_update_period;
        u32 pmf_qos;
        u32 arp_ac_override;
-       u32 arpdhcp_ac_override;
        u32 dcs;
        u32 ani_enable;
        u32 ani_poll_period;
@@ -3403,6 +3402,24 @@ struct wmi_bcn_tx_arg {
        const void *bcn;
 };
 
+enum wmi_bcn_tx_ref_flags {
+       WMI_BCN_TX_REF_FLAG_DTIM_ZERO = 0x1,
+       WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
+};
+
+struct wmi_bcn_tx_ref_cmd {
+       __le32 vdev_id;
+       __le32 data_len;
+       /* physical address of the frame - dma pointer */
+       __le32 data_ptr;
+       /* id for host to track */
+       __le32 msdu_id;
+       /* frame ctrl to setup PPDU desc */
+       __le32 frame_control;
+       /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
+       __le32 flags;
+} __packed;
+
 /* Beacon filter */
 #define WMI_BCN_FILTER_ALL   0 /* Filter all beacons */
 #define WMI_BCN_FILTER_NONE  1 /* Pass all beacons */
@@ -3859,6 +3876,12 @@ enum wmi_peer_smps_state {
        WMI_PEER_SMPS_DYNAMIC = 0x2
 };
 
+enum wmi_peer_chwidth {
+       WMI_PEER_CHWIDTH_20MHZ = 0,
+       WMI_PEER_CHWIDTH_40MHZ = 1,
+       WMI_PEER_CHWIDTH_80MHZ = 2,
+};
+
 enum wmi_peer_param {
        WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */
        WMI_PEER_AMPDU      = 0x2,
@@ -4039,6 +4062,10 @@ struct wmi_chan_info_event {
        __le32 cycle_count;
 } __packed;
 
+struct wmi_peer_sta_kickout_event {
+       struct wmi_mac_addr peer_macaddr;
+} __packed;
+
 #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
 
 /* FIXME: empirically extrapolated */
@@ -4172,7 +4199,7 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
 int ath10k_wmi_connect_htc_service(struct ath10k *ar);
 int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
                                const struct wmi_channel_arg *);
-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar);
+int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
 int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
 int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
                                  u16 rd5g, u16 ctl2g, u16 ctl5g);
@@ -4219,8 +4246,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
                               enum wmi_ap_ps_peer_param param_id, u32 value);
 int ath10k_wmi_scan_chan_list(struct ath10k *ar,
                              const struct wmi_scan_chan_list_arg *arg);
-int ath10k_wmi_beacon_send_nowait(struct ath10k *ar,
-                                 const struct wmi_bcn_tx_arg *arg);
+int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
 int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
                        const struct wmi_pdev_set_wmm_params_arg *arg);
 int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
index 4ee01f654235478ea3510847d6f207593541573f..afb23b3cc7be64d6b0ae8f79d46a3a9c9d07eab3 100644 (file)
@@ -681,6 +681,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
        survey->channel = conf->chandef.chan;
        survey->noise = ah->ah_noise_floor;
        survey->filled = SURVEY_INFO_NOISE_DBM |
+                       SURVEY_INFO_IN_USE |
                        SURVEY_INFO_CHANNEL_TIME |
                        SURVEY_INFO_CHANNEL_TIME_BUSY |
                        SURVEY_INFO_CHANNEL_TIME_RX |
index f38ff6a6255e7be58c4687a2ff85115c8250225c..56c3fd5cef65a07e915d63d8c0dc24727a87406b 100644 (file)
@@ -24,7 +24,7 @@
 /* constants */
 #define TX_URB_COUNT            32
 #define RX_URB_COUNT            32
-#define ATH6KL_USB_RX_BUFFER_SIZE  1700
+#define ATH6KL_USB_RX_BUFFER_SIZE  4096
 
 /* tx/rx pipes for usb */
 enum ATH6KL_USB_PIPE_ID {
@@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb)
         *              ATH6KL_USB_RX_BUFFER_SIZE);
         */
 
-       ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh =
-           ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2;
+       ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 1;
+
        ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA],
                                       ATH6KL_USB_RX_BUFFER_SIZE);
 }
index 4f16d79c9eb187566ff878e9ac42c163cd58312a..8b4ce28e3ce8f51f7cda070364394a117d5aef66 100644 (file)
@@ -914,7 +914,7 @@ ath6kl_get_regpair(u16 regdmn)
                return NULL;
 
        for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
-               if (regDomainPairs[i].regDmnEnum == regdmn)
+               if (regDomainPairs[i].reg_domain == regdmn)
                        return &regDomainPairs[i];
        }
 
@@ -954,7 +954,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
                country = ath6kl_regd_find_country_by_rd((u16) reg_code);
                if (regpair)
                        ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
-                                  regpair->regDmnEnum);
+                                  regpair->reg_domain);
                else
                        ath6kl_warn("Regpair not found reg_code 0x%0x\n",
                                    reg_code);
index 747975e1860a74d38ea64ba8640ad3e38f63be6b..b58fe99ef74559aa8b5d03daf94bcc20eb927990 100644 (file)
@@ -51,7 +51,8 @@ ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
 obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
 
 obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o
-ath9k_common-y:=       common.o
+ath9k_common-y:=       common.o \
+                       common-init.o
 
 ath9k_htc-y += htc_hst.o \
                hif_usb.o \
index d28923b7435b257f13a91e3f8896115c30adb1c9..2ce5079007b6800e331da1eb20eca8b45692b83e 100644 (file)
@@ -176,16 +176,26 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
        if (ah->opmode == NL80211_IFTYPE_STATION &&
            BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
                weak_sig = true;
-
        /*
-        * OFDM Weak signal detection is always enabled for AP mode.
+        * Newer chipsets are better at dealing with high PHY error counts -
+        * keep weak signal detection enabled when no RSSI threshold is
+        * available to determine if it is needed (mode != STA)
         */
-       if (ah->opmode != NL80211_IFTYPE_AP &&
-           aniState->ofdmWeakSigDetect != weak_sig) {
-               ath9k_hw_ani_control(ah,
-                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                    entry_ofdm->ofdm_weak_signal_on);
-       }
+       else if (AR_SREV_9300_20_OR_LATER(ah) &&
+                ah->opmode != NL80211_IFTYPE_STATION)
+               weak_sig = true;
+
+       /* Older chipsets are more sensitive to high PHY error counts */
+       else if (!AR_SREV_9300_20_OR_LATER(ah) &&
+                aniState->ofdmNoiseImmunityLevel >= 8)
+               weak_sig = false;
+
+       if (aniState->ofdmWeakSigDetect != weak_sig)
+               ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+                                    weak_sig);
+
+       if (!AR_SREV_9300_20_OR_LATER(ah))
+               return;
 
        if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
                ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
@@ -483,10 +493,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
 
        ath_dbg(common, ANI, "Initialize ANI\n");
 
-       ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
-       ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
-       ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
-       ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
+               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
+               ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
+               ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
+       } else {
+               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
+               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
+               ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
+               ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
+       }
 
        ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
        ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
index 21e7b83c3f6ac85e881b49b315256e931728ec7e..c40965b4c1e2982859cc2fff8f1e7f4747f376e7 100644 (file)
 /* units are errors per second */
 #define ATH9K_ANI_OFDM_TRIG_HIGH           3500
 #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000
+#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD       500
 
 #define ATH9K_ANI_OFDM_TRIG_LOW           400
 #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900
+#define ATH9K_ANI_OFDM_TRIG_LOW_OLD       200
 
 #define ATH9K_ANI_CCK_TRIG_HIGH           600
+#define ATH9K_ANI_CCK_TRIG_HIGH_OLD       200
 #define ATH9K_ANI_CCK_TRIG_LOW            300
+#define ATH9K_ANI_CCK_TRIG_LOW_OLD        100
 
 #define ATH9K_ANI_SPUR_IMMUNE_LVL         3
 #define ATH9K_ANI_FIRSTEP_LVL             2
index 09facba1dc6d8069583f0eb0fdf41e59d96a15f8..8927fc34d84c2f009e192dc9a37cb140be941e54 100644 (file)
@@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah,
 
        if (IS_CHAN_A_FAST_CLOCK(ah, chan))
                rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
-       if (IS_CHAN_QUARTER_RATE(chan))
-               rfMode |= AR_PHY_MODE_QUARTER;
-       if (IS_CHAN_HALF_RATE(chan))
-               rfMode |= AR_PHY_MODE_HALF;
 
        if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
                REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
index 1cc13569b17b8ed7126a9aae49a2d519c360337b..1b6b4d0cfa97a5df8c2a7e0d631c417377ba17b2 100644 (file)
@@ -57,7 +57,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
-       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+       {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},
        {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
        {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
        {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
@@ -96,7 +96,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},
        {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
-       {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+       {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa},
        {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
 };
 
index 21d13bc99c5a4ad77a4f9d4257abc4781e14808d..f995c374a9b4336e242d3f0de902892f40c12292 100644 (file)
@@ -410,7 +410,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
 
 struct ath_beacon_config {
        int beacon_interval;
-       u16 listen_interval;
        u16 dtim_period;
        u16 bmiss_timeout;
        u8 dtim_count;
@@ -753,7 +752,6 @@ struct ath_softc {
        struct ath_rx rx;
        struct ath_tx tx;
        struct ath_beacon beacon;
-       struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
 
 #ifdef CONFIG_MAC80211_LEDS
        bool led_registered;
index 32d00e8cfd0c862e8854be050faa924d9bf75beb..02eb4f10332bc6e6b420127baafaf16d86690f1e 100644 (file)
@@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
        u8 chainmask = ah->txchainmask;
        u8 rate = 0;
 
-       sband = &sc->sbands[common->hw->conf.chandef.chan->band];
+       sband = &common->sbands[common->hw->conf.chandef.chan->band];
        rate = sband->bitrates[rateidx].hw_value;
        if (vif->bss_conf.use_short_preamble)
                rate |= sband->bitrates[rateidx].hw_value_short;
@@ -519,7 +519,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_beacon_state bs;
-       int dtim_intval, sleepduration;
+       int dtim_intval;
        u32 nexttbtt = 0, intval;
        u64 tsf;
 
@@ -538,7 +538,6 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
         * last beacon we received (which may be none).
         */
        dtim_intval = intval * conf->dtim_period;
-       sleepduration = conf->listen_interval * intval;
 
        /*
         * Pull nexttbtt forward to reflect the current
@@ -560,16 +559,11 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
         * need calculate based on the beacon interval.  Note that we clamp the
         * result to at most 15 beacons.
         */
-       if (sleepduration > intval) {
-               bs.bs_bmissthreshold = conf->listen_interval *
-                       ATH_DEFAULT_BMISS_LIMIT / 2;
-       } else {
-               bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
-               if (bs.bs_bmissthreshold > 15)
-                       bs.bs_bmissthreshold = 15;
-               else if (bs.bs_bmissthreshold <= 0)
-                       bs.bs_bmissthreshold = 1;
-       }
+       bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
+       if (bs.bs_bmissthreshold > 15)
+               bs.bs_bmissthreshold = 15;
+       else if (bs.bs_bmissthreshold <= 0)
+               bs.bs_bmissthreshold = 1;
 
        /*
         * Calculate sleep duration. The configuration is given in ms.
@@ -581,7 +575,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
         */
 
        bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
-                                                sleepduration));
+                                                intval));
        if (bs.bs_sleepduration > bs.bs_dtimperiod)
                bs.bs_sleepduration = bs.bs_dtimperiod;
 
@@ -677,7 +671,6 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
 
        cur_conf->beacon_interval = bss_conf->beacon_int;
        cur_conf->dtim_period = bss_conf->dtim_period;
-       cur_conf->listen_interval = 1;
        cur_conf->dtim_count = 1;
        cur_conf->ibss_creator = bss_conf->ibss_creator;
        cur_conf->bmiss_timeout =
diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c
new file mode 100644 (file)
index 0000000..a006c14
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* We use the hw_value as an index into our private channel structure */
+
+#include "common.h"
+
+#define CHAN2G(_freq, _idx)  { \
+       .band = IEEE80211_BAND_2GHZ, \
+       .center_freq = (_freq), \
+       .hw_value = (_idx), \
+       .max_power = 20, \
+}
+
+#define CHAN5G(_freq, _idx) { \
+       .band = IEEE80211_BAND_5GHZ, \
+       .center_freq = (_freq), \
+       .hw_value = (_idx), \
+       .max_power = 20, \
+}
+
+/* Some 2 GHz radios are actually tunable on 2312-2732
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
+       CHAN2G(2412, 0), /* Channel 1 */
+       CHAN2G(2417, 1), /* Channel 2 */
+       CHAN2G(2422, 2), /* Channel 3 */
+       CHAN2G(2427, 3), /* Channel 4 */
+       CHAN2G(2432, 4), /* Channel 5 */
+       CHAN2G(2437, 5), /* Channel 6 */
+       CHAN2G(2442, 6), /* Channel 7 */
+       CHAN2G(2447, 7), /* Channel 8 */
+       CHAN2G(2452, 8), /* Channel 9 */
+       CHAN2G(2457, 9), /* Channel 10 */
+       CHAN2G(2462, 10), /* Channel 11 */
+       CHAN2G(2467, 11), /* Channel 12 */
+       CHAN2G(2472, 12), /* Channel 13 */
+       CHAN2G(2484, 13), /* Channel 14 */
+};
+
+/* Some 5 GHz radios are actually tunable on XXXX-YYYY
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
+       /* _We_ call this UNII 1 */
+       CHAN5G(5180, 14), /* Channel 36 */
+       CHAN5G(5200, 15), /* Channel 40 */
+       CHAN5G(5220, 16), /* Channel 44 */
+       CHAN5G(5240, 17), /* Channel 48 */
+       /* _We_ call this UNII 2 */
+       CHAN5G(5260, 18), /* Channel 52 */
+       CHAN5G(5280, 19), /* Channel 56 */
+       CHAN5G(5300, 20), /* Channel 60 */
+       CHAN5G(5320, 21), /* Channel 64 */
+       /* _We_ call this "Middle band" */
+       CHAN5G(5500, 22), /* Channel 100 */
+       CHAN5G(5520, 23), /* Channel 104 */
+       CHAN5G(5540, 24), /* Channel 108 */
+       CHAN5G(5560, 25), /* Channel 112 */
+       CHAN5G(5580, 26), /* Channel 116 */
+       CHAN5G(5600, 27), /* Channel 120 */
+       CHAN5G(5620, 28), /* Channel 124 */
+       CHAN5G(5640, 29), /* Channel 128 */
+       CHAN5G(5660, 30), /* Channel 132 */
+       CHAN5G(5680, 31), /* Channel 136 */
+       CHAN5G(5700, 32), /* Channel 140 */
+       /* _We_ call this UNII 3 */
+       CHAN5G(5745, 33), /* Channel 149 */
+       CHAN5G(5765, 34), /* Channel 153 */
+       CHAN5G(5785, 35), /* Channel 157 */
+       CHAN5G(5805, 36), /* Channel 161 */
+       CHAN5G(5825, 37), /* Channel 165 */
+};
+
+/* Atheros hardware rate code addition for short premble */
+#define SHPCHECK(__hw_rate, __flags) \
+       ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
+
+#define RATE(_bitrate, _hw_rate, _flags) {              \
+       .bitrate        = (_bitrate),                   \
+       .flags          = (_flags),                     \
+       .hw_value       = (_hw_rate),                   \
+       .hw_value_short = (SHPCHECK(_hw_rate, _flags))  \
+}
+
+static struct ieee80211_rate ath9k_legacy_rates[] = {
+       RATE(10, 0x1b, 0),
+       RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ |
+                       IEEE80211_RATE_SUPPORTS_10MHZ)),
+       RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ |
+                       IEEE80211_RATE_SUPPORTS_10MHZ)),
+       RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ |
+                        IEEE80211_RATE_SUPPORTS_10MHZ)),
+       RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ |
+                        IEEE80211_RATE_SUPPORTS_10MHZ)),
+       RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ |
+                        IEEE80211_RATE_SUPPORTS_10MHZ)),
+       RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ |
+                        IEEE80211_RATE_SUPPORTS_10MHZ)),
+       RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ |
+                        IEEE80211_RATE_SUPPORTS_10MHZ)),
+       RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ |
+                        IEEE80211_RATE_SUPPORTS_10MHZ)),
+};
+
+int ath9k_cmn_init_channels_rates(struct ath_common *common)
+{
+       struct ath_hw *ah = (struct ath_hw *)common->ah;
+       void *channels;
+
+       BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
+                    ARRAY_SIZE(ath9k_5ghz_chantable) !=
+                    ATH9K_NUM_CHANNELS);
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
+               channels = devm_kzalloc(ah->dev,
+                       sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
+               if (!channels)
+                   return -ENOMEM;
+
+               memcpy(channels, ath9k_2ghz_chantable,
+                      sizeof(ath9k_2ghz_chantable));
+               common->sbands[IEEE80211_BAND_2GHZ].channels = channels;
+               common->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+               common->sbands[IEEE80211_BAND_2GHZ].n_channels =
+                       ARRAY_SIZE(ath9k_2ghz_chantable);
+               common->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
+               common->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
+                       ARRAY_SIZE(ath9k_legacy_rates);
+       }
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
+               channels = devm_kzalloc(ah->dev,
+                       sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
+               if (!channels)
+                       return -ENOMEM;
+
+               memcpy(channels, ath9k_5ghz_chantable,
+                      sizeof(ath9k_5ghz_chantable));
+               common->sbands[IEEE80211_BAND_5GHZ].channels = channels;
+               common->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+               common->sbands[IEEE80211_BAND_5GHZ].n_channels =
+                       ARRAY_SIZE(ath9k_5ghz_chantable);
+               common->sbands[IEEE80211_BAND_5GHZ].bitrates =
+                       ath9k_legacy_rates + 4;
+               common->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
+                       ARRAY_SIZE(ath9k_legacy_rates) - 4;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(ath9k_cmn_init_channels_rates);
+
+void ath9k_cmn_setup_ht_cap(struct ath_hw *ah,
+                           struct ieee80211_sta_ht_cap *ht_info)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u8 tx_streams, rx_streams;
+       int i, max_streams;
+
+       ht_info->ht_supported = true;
+       ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                      IEEE80211_HT_CAP_SM_PS |
+                      IEEE80211_HT_CAP_SGI_40 |
+                      IEEE80211_HT_CAP_DSSSCCK40;
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
+               ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+               ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
+       ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+       ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
+
+       if (AR_SREV_9271(ah) || AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah))
+               max_streams = 1;
+       else if (AR_SREV_9462(ah))
+               max_streams = 2;
+       else if (AR_SREV_9300_20_OR_LATER(ah))
+               max_streams = 3;
+       else
+               max_streams = 2;
+
+       if (AR_SREV_9280_20_OR_LATER(ah)) {
+               if (max_streams >= 2)
+                       ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+               ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+       }
+
+       /* set up supported mcs set */
+       memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+       tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams);
+       rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams);
+
+       ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
+               tx_streams, rx_streams);
+
+       if (tx_streams != rx_streams) {
+               ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+               ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+       }
+
+       for (i = 0; i < rx_streams; i++)
+               ht_info->mcs.rx_mask[i] = 0xff;
+
+       ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
+}
+EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap);
+
+void ath9k_cmn_reload_chainmask(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT))
+               return;
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
+               ath9k_cmn_setup_ht_cap(ah,
+                       &common->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
+               ath9k_cmn_setup_ht_cap(ah,
+                       &common->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+}
+EXPORT_SYMBOL(ath9k_cmn_reload_chainmask);
diff --git a/drivers/net/wireless/ath/ath9k/common-init.h b/drivers/net/wireless/ath/ath9k/common-init.h
new file mode 100644 (file)
index 0000000..ac03fca
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+int ath9k_cmn_init_channels_rates(struct ath_common *common);
+void ath9k_cmn_setup_ht_cap(struct ath_hw *ah,
+                           struct ieee80211_sta_ht_cap *ht_info);
+void ath9k_cmn_reload_chainmask(struct ath_hw *ah);
index 38b5609a4018fd33c3fbd148b35cc5df19c69721..4c449e35bd6552f9a7f2191b089f493da5bdbc7d 100644 (file)
@@ -21,6 +21,8 @@
 #include "hw.h"
 #include "hw-ops.h"
 
+#include "common-init.h"
+
 /* Common header for Atheros 802.11n base driver cores */
 
 #define WME_BA_BMP_SIZE         64
index ab7264c1d8f73904ac9005fc19ec6d6aa3e30b30..f8924efdad551d149bfdd12abc63c245bfa3c158 100644 (file)
@@ -135,7 +135,8 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,
        struct ath_softc *sc = file->private_data;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_hw *ah = sc->sc_ah;
-       unsigned int len = 0, size = 1024;
+       unsigned int len = 0;
+       const unsigned int size = 1024;
        ssize_t retval = 0;
        char *buf;
 
@@ -307,13 +308,13 @@ static ssize_t read_file_antenna_diversity(struct file *file,
        struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];
        struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
        struct ath_hw_antcomb_conf div_ant_conf;
-       unsigned int len = 0, size = 1024;
+       unsigned int len = 0;
+       const unsigned int size = 1024;
        ssize_t retval = 0;
        char *buf;
-       char *lna_conf_str[4] = {"LNA1_MINUS_LNA2",
-                                "LNA2",
-                                "LNA1",
-                                "LNA1_PLUS_LNA2"};
+       static const char *lna_conf_str[4] = {
+               "LNA1_MINUS_LNA2", "LNA2", "LNA1", "LNA1_PLUS_LNA2"
+       };
 
        buf = kzalloc(size, GFP_KERNEL);
        if (buf == NULL)
@@ -716,10 +717,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf,
        struct ath_softc *sc = file->private_data;
        struct ath_txq *txq;
        char *buf;
-       unsigned int len = 0, size = 1024;
+       unsigned int len = 0;
+       const unsigned int size = 1024;
        ssize_t retval = 0;
        int i;
-       char *qname[4] = {"VO", "VI", "BE", "BK"};
+       static const char *qname[4] = {
+               "VO", "VI", "BE", "BK"
+       };
 
        buf = kzalloc(size, GFP_KERNEL);
        if (buf == NULL)
@@ -865,6 +869,12 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
        len += scnprintf(buf + len, sizeof(buf) - len,
                         "%17s: %2d\n", "PLL RX Hang",
                         sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%17s: %2d\n", "MAC Hang",
+                        sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%17s: %2d\n", "Stuck Beacon",
+                        sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
        len += scnprintf(buf + len, sizeof(buf) - len,
                         "%17s: %2d\n", "MCI Reset",
                         sc->debug.stats.reset[RESET_TYPE_MCI]);
index ba83f582bf4a71c74b676a38f82e209125d1cec2..3baf9ceae601bce75cd4f5fe99eaf8d128307325 100644 (file)
@@ -487,7 +487,6 @@ struct ath9k_htc_priv {
        unsigned long op_flags;
 
        struct ath9k_hw_cal_data caldata;
-       struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
 
        spinlock_t beacon_lock;
        struct htc_beacon_config cur_beacon_conf;
index 8b575773459677055fe6b427e8443f65796c4ae2..a00ddb9e737ed46fea8b72bf71139ddef12e7574 100644 (file)
@@ -69,7 +69,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
        struct ath_common *common = ath9k_hw_common(priv->ah);
        struct ath9k_beacon_state bs;
        enum ath9k_int imask = 0;
-       int dtimperiod, dtimcount, sleepduration;
+       int dtimperiod, dtimcount;
        int bmiss_timeout;
        u32 nexttbtt = 0, intval, tsftu;
        __be32 htc_imask = 0;
@@ -94,10 +94,6 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
        if (dtimcount >= dtimperiod)    /* NB: sanity check */
                dtimcount = 0;
 
-       sleepduration = intval;
-       if (sleepduration <= 0)
-               sleepduration = intval;
-
        /*
         * Pull nexttbtt forward to reflect the current
         * TSF and calculate dtim state for the result.
@@ -128,15 +124,11 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
         * need calculate based on the beacon interval.  Note that we clamp the
         * result to at most 15 beacons.
         */
-       if (sleepduration > intval) {
-               bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2;
-       } else {
-               bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
-               if (bs.bs_bmissthreshold > 15)
-                       bs.bs_bmissthreshold = 15;
-               else if (bs.bs_bmissthreshold <= 0)
-                       bs.bs_bmissthreshold = 1;
-       }
+       bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
+       if (bs.bs_bmissthreshold > 15)
+               bs.bs_bmissthreshold = 15;
+       else if (bs.bs_bmissthreshold <= 0)
+               bs.bs_bmissthreshold = 1;
 
        /*
         * Calculate sleep duration. The configuration is given in ms.
@@ -148,7 +140,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
         */
 
        bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
-                                                sleepduration));
+                                                intval));
        if (bs.bs_sleepduration > bs.bs_dtimperiod)
                bs.bs_sleepduration = bs.bs_dtimperiod;
 
index 8d0b9bcb47b465059399bfaea0589406751e906b..b22fb64403d9362de0771a9ebd9b07ed13bedae7 100644 (file)
@@ -38,93 +38,6 @@ static int ath9k_ps_enable;
 module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
 MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
 
-#define CHAN2G(_freq, _idx)  { \
-       .center_freq = (_freq), \
-       .hw_value = (_idx), \
-       .max_power = 20, \
-}
-
-#define CHAN5G(_freq, _idx) { \
-       .band = IEEE80211_BAND_5GHZ, \
-       .center_freq = (_freq), \
-       .hw_value = (_idx), \
-       .max_power = 20, \
-}
-
-static struct ieee80211_channel ath9k_2ghz_channels[] = {
-       CHAN2G(2412, 0), /* Channel 1 */
-       CHAN2G(2417, 1), /* Channel 2 */
-       CHAN2G(2422, 2), /* Channel 3 */
-       CHAN2G(2427, 3), /* Channel 4 */
-       CHAN2G(2432, 4), /* Channel 5 */
-       CHAN2G(2437, 5), /* Channel 6 */
-       CHAN2G(2442, 6), /* Channel 7 */
-       CHAN2G(2447, 7), /* Channel 8 */
-       CHAN2G(2452, 8), /* Channel 9 */
-       CHAN2G(2457, 9), /* Channel 10 */
-       CHAN2G(2462, 10), /* Channel 11 */
-       CHAN2G(2467, 11), /* Channel 12 */
-       CHAN2G(2472, 12), /* Channel 13 */
-       CHAN2G(2484, 13), /* Channel 14 */
-};
-
-static struct ieee80211_channel ath9k_5ghz_channels[] = {
-       /* _We_ call this UNII 1 */
-       CHAN5G(5180, 14), /* Channel 36 */
-       CHAN5G(5200, 15), /* Channel 40 */
-       CHAN5G(5220, 16), /* Channel 44 */
-       CHAN5G(5240, 17), /* Channel 48 */
-       /* _We_ call this UNII 2 */
-       CHAN5G(5260, 18), /* Channel 52 */
-       CHAN5G(5280, 19), /* Channel 56 */
-       CHAN5G(5300, 20), /* Channel 60 */
-       CHAN5G(5320, 21), /* Channel 64 */
-       /* _We_ call this "Middle band" */
-       CHAN5G(5500, 22), /* Channel 100 */
-       CHAN5G(5520, 23), /* Channel 104 */
-       CHAN5G(5540, 24), /* Channel 108 */
-       CHAN5G(5560, 25), /* Channel 112 */
-       CHAN5G(5580, 26), /* Channel 116 */
-       CHAN5G(5600, 27), /* Channel 120 */
-       CHAN5G(5620, 28), /* Channel 124 */
-       CHAN5G(5640, 29), /* Channel 128 */
-       CHAN5G(5660, 30), /* Channel 132 */
-       CHAN5G(5680, 31), /* Channel 136 */
-       CHAN5G(5700, 32), /* Channel 140 */
-       /* _We_ call this UNII 3 */
-       CHAN5G(5745, 33), /* Channel 149 */
-       CHAN5G(5765, 34), /* Channel 153 */
-       CHAN5G(5785, 35), /* Channel 157 */
-       CHAN5G(5805, 36), /* Channel 161 */
-       CHAN5G(5825, 37), /* Channel 165 */
-};
-
-/* Atheros hardware rate code addition for short premble */
-#define SHPCHECK(__hw_rate, __flags) \
-       ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
-
-#define RATE(_bitrate, _hw_rate, _flags) {             \
-       .bitrate        = (_bitrate),                   \
-       .flags          = (_flags),                     \
-       .hw_value       = (_hw_rate),                   \
-       .hw_value_short = (SHPCHECK(_hw_rate, _flags))  \
-}
-
-static struct ieee80211_rate ath9k_legacy_rates[] = {
-       RATE(10, 0x1b, 0),
-       RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */
-       RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */
-       RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */
-       RATE(60, 0x0b, 0),
-       RATE(90, 0x0f, 0),
-       RATE(120, 0x0a, 0),
-       RATE(180, 0x0e, 0),
-       RATE(240, 0x09, 0),
-       RATE(360, 0x0d, 0),
-       RATE(480, 0x08, 0),
-       RATE(540, 0x0c, 0),
-};
-
 #ifdef CONFIG_MAC80211_LEDS
 static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
        { .throughput = 0 * 1024, .blink_time = 334 },
@@ -343,6 +256,25 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr,
        }
 }
 
+static void ath9k_regwrite_multi(struct ath_common *common)
+{
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+       u32 rsp_status;
+       int r;
+
+       r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
+                         (u8 *) &priv->wmi->multi_write,
+                         sizeof(struct register_write) * priv->wmi->multi_write_idx,
+                         (u8 *) &rsp_status, sizeof(rsp_status),
+                         100);
+       if (unlikely(r)) {
+               ath_dbg(common, WMI,
+                       "REGISTER WRITE FAILED, multi len: %d\n",
+                       priv->wmi->multi_write_idx);
+       }
+       priv->wmi->multi_write_idx = 0;
+}
+
 static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
 {
        struct ath_hw *ah = (struct ath_hw *) hw_priv;
@@ -369,8 +301,6 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
        struct ath_hw *ah = (struct ath_hw *) hw_priv;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-       u32 rsp_status;
-       int r;
 
        mutex_lock(&priv->wmi->multi_write_mutex);
 
@@ -383,19 +313,8 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
        priv->wmi->multi_write_idx++;
 
        /* If the buffer is full, send it out. */
-       if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
-               r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
-                         (u8 *) &priv->wmi->multi_write,
-                         sizeof(struct register_write) * priv->wmi->multi_write_idx,
-                         (u8 *) &rsp_status, sizeof(rsp_status),
-                         100);
-               if (unlikely(r)) {
-                       ath_dbg(common, WMI,
-                               "REGISTER WRITE FAILED, multi len: %d\n",
-                               priv->wmi->multi_write_idx);
-               }
-               priv->wmi->multi_write_idx = 0;
-       }
+       if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER)
+               ath9k_regwrite_multi(common);
 
        mutex_unlock(&priv->wmi->multi_write_mutex);
 }
@@ -426,26 +345,13 @@ static void ath9k_regwrite_flush(void *hw_priv)
        struct ath_hw *ah = (struct ath_hw *) hw_priv;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-       u32 rsp_status;
-       int r;
 
        atomic_dec(&priv->wmi->mwrite_cnt);
 
        mutex_lock(&priv->wmi->multi_write_mutex);
 
-       if (priv->wmi->multi_write_idx) {
-               r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
-                         (u8 *) &priv->wmi->multi_write,
-                         sizeof(struct register_write) * priv->wmi->multi_write_idx,
-                         (u8 *) &rsp_status, sizeof(rsp_status),
-                         100);
-               if (unlikely(r)) {
-                       ath_dbg(common, WMI,
-                               "REGISTER WRITE FAILED, multi len: %d\n",
-                               priv->wmi->multi_write_idx);
-               }
-               priv->wmi->multi_write_idx = 0;
-       }
+       if (priv->wmi->multi_write_idx)
+               ath9k_regwrite_multi(common);
 
        mutex_unlock(&priv->wmi->multi_write_mutex);
 }
@@ -491,51 +397,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = {
        .eeprom_read = ath_usb_eeprom_read,
 };
 
-static void setup_ht_cap(struct ath9k_htc_priv *priv,
-                        struct ieee80211_sta_ht_cap *ht_info)
-{
-       struct ath_common *common = ath9k_hw_common(priv->ah);
-       u8 tx_streams, rx_streams;
-       int i;
-
-       ht_info->ht_supported = true;
-       ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
-                      IEEE80211_HT_CAP_SM_PS |
-                      IEEE80211_HT_CAP_SGI_40 |
-                      IEEE80211_HT_CAP_DSSSCCK40;
-
-       if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
-               ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
-
-       ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
-
-       ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
-       ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
-
-       memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-
-       /* ath9k_htc supports only 1 or 2 stream devices */
-       tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2);
-       rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2);
-
-       ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
-               tx_streams, rx_streams);
-
-       if (tx_streams >= 2)
-               ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
-
-       if (tx_streams != rx_streams) {
-               ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
-               ht_info->mcs.tx_params |= ((tx_streams - 1) <<
-                                          IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
-       }
-
-       for (i = 0; i < rx_streams; i++)
-               ht_info->mcs.rx_mask[i] = 0xff;
-
-       ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
-}
-
 static int ath9k_init_queues(struct ath9k_htc_priv *priv)
 {
        struct ath_common *common = ath9k_hw_common(priv->ah);
@@ -580,31 +441,6 @@ err:
        return -EINVAL;
 }
 
-static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
-{
-       if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
-               priv->sbands[IEEE80211_BAND_2GHZ].channels =
-                       ath9k_2ghz_channels;
-               priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
-               priv->sbands[IEEE80211_BAND_2GHZ].n_channels =
-                       ARRAY_SIZE(ath9k_2ghz_channels);
-               priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
-               priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
-                       ARRAY_SIZE(ath9k_legacy_rates);
-       }
-
-       if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
-               priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
-               priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
-               priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
-                       ARRAY_SIZE(ath9k_5ghz_channels);
-               priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
-                       ath9k_legacy_rates + 4;
-               priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
-                       ARRAY_SIZE(ath9k_legacy_rates) - 4;
-       }
-}
-
 static void ath9k_init_misc(struct ath9k_htc_priv *priv)
 {
        struct ath_common *common = ath9k_hw_common(priv->ah);
@@ -629,6 +465,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
        if (!ah)
                return -ENOMEM;
 
+       ah->dev = priv->dev;
        ah->hw_version.devid = devid;
        ah->hw_version.usbdev = drv_info;
        ah->ah_flags |= AH_USE_EEPROM;
@@ -685,8 +522,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
        for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
                priv->cur_beacon_conf.bslot[i] = NULL;
 
+       ath9k_cmn_init_channels_rates(common);
        ath9k_cmn_init_crypto(ah);
-       ath9k_init_channels_rates(priv);
        ath9k_init_misc(priv);
        ath9k_htc_init_btcoex(priv, product);
 
@@ -722,6 +559,7 @@ static const struct ieee80211_iface_combination if_comb = {
 static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
                               struct ieee80211_hw *hw)
 {
+       struct ath_hw *ah = priv->ah;
        struct ath_common *common = ath9k_hw_common(priv->ah);
        struct base_eep_header *pBase;
 
@@ -766,19 +604,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
 
        if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
                hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-                       &priv->sbands[IEEE80211_BAND_2GHZ];
+                       &common->sbands[IEEE80211_BAND_2GHZ];
        if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
                hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       &priv->sbands[IEEE80211_BAND_5GHZ];
-
-       if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
-               if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
-                       setup_ht_cap(priv,
-                                    &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
-               if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
-                       setup_ht_cap(priv,
-                                    &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
-       }
+                       &common->sbands[IEEE80211_BAND_5GHZ];
+
+       ath9k_cmn_reload_chainmask(ah);
 
        pBase = ath9k_htc_get_eeprom_base(priv);
        if (pBase) {
index 5db01b4212c8201383473bfdf886137f02b41491..2509c2ff08286569a0f7f93993791a5994c9c942 100644 (file)
@@ -1533,7 +1533,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav);
 bool ath9k_hw_check_alive(struct ath_hw *ah)
 {
        int count = 50;
-       u32 reg;
+       u32 reg, last_val;
 
        if (AR_SREV_9300(ah))
                return !ath9k_hw_detect_mac_hang(ah);
@@ -1541,9 +1541,13 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
        if (AR_SREV_9285_12_OR_LATER(ah))
                return true;
 
+       last_val = REG_READ(ah, AR_OBS_BUS_1);
        do {
                reg = REG_READ(ah, AR_OBS_BUS_1);
+               if (reg != last_val)
+                       return true;
 
+               last_val = reg;
                if ((reg & 0x7E7FFFEF) == 0x00702400)
                        continue;
 
@@ -1555,6 +1559,8 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
                default:
                        return true;
                }
+
+               udelay(1);
        } while (count-- > 0);
 
        return false;
index 07a0315dd2f64baff254e18da191c273c32e4173..c0a4e866edcac9b5325a497d6e7bdedfdadb3b66 100644 (file)
@@ -62,111 +62,6 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
 MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
 
 bool is_ath9k_unloaded;
-/* We use the hw_value as an index into our private channel structure */
-
-#define CHAN2G(_freq, _idx)  { \
-       .band = IEEE80211_BAND_2GHZ, \
-       .center_freq = (_freq), \
-       .hw_value = (_idx), \
-       .max_power = 20, \
-}
-
-#define CHAN5G(_freq, _idx) { \
-       .band = IEEE80211_BAND_5GHZ, \
-       .center_freq = (_freq), \
-       .hw_value = (_idx), \
-       .max_power = 20, \
-}
-
-/* Some 2 GHz radios are actually tunable on 2312-2732
- * on 5 MHz steps, we support the channels which we know
- * we have calibration data for all cards though to make
- * this static */
-static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
-       CHAN2G(2412, 0), /* Channel 1 */
-       CHAN2G(2417, 1), /* Channel 2 */
-       CHAN2G(2422, 2), /* Channel 3 */
-       CHAN2G(2427, 3), /* Channel 4 */
-       CHAN2G(2432, 4), /* Channel 5 */
-       CHAN2G(2437, 5), /* Channel 6 */
-       CHAN2G(2442, 6), /* Channel 7 */
-       CHAN2G(2447, 7), /* Channel 8 */
-       CHAN2G(2452, 8), /* Channel 9 */
-       CHAN2G(2457, 9), /* Channel 10 */
-       CHAN2G(2462, 10), /* Channel 11 */
-       CHAN2G(2467, 11), /* Channel 12 */
-       CHAN2G(2472, 12), /* Channel 13 */
-       CHAN2G(2484, 13), /* Channel 14 */
-};
-
-/* Some 5 GHz radios are actually tunable on XXXX-YYYY
- * on 5 MHz steps, we support the channels which we know
- * we have calibration data for all cards though to make
- * this static */
-static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
-       /* _We_ call this UNII 1 */
-       CHAN5G(5180, 14), /* Channel 36 */
-       CHAN5G(5200, 15), /* Channel 40 */
-       CHAN5G(5220, 16), /* Channel 44 */
-       CHAN5G(5240, 17), /* Channel 48 */
-       /* _We_ call this UNII 2 */
-       CHAN5G(5260, 18), /* Channel 52 */
-       CHAN5G(5280, 19), /* Channel 56 */
-       CHAN5G(5300, 20), /* Channel 60 */
-       CHAN5G(5320, 21), /* Channel 64 */
-       /* _We_ call this "Middle band" */
-       CHAN5G(5500, 22), /* Channel 100 */
-       CHAN5G(5520, 23), /* Channel 104 */
-       CHAN5G(5540, 24), /* Channel 108 */
-       CHAN5G(5560, 25), /* Channel 112 */
-       CHAN5G(5580, 26), /* Channel 116 */
-       CHAN5G(5600, 27), /* Channel 120 */
-       CHAN5G(5620, 28), /* Channel 124 */
-       CHAN5G(5640, 29), /* Channel 128 */
-       CHAN5G(5660, 30), /* Channel 132 */
-       CHAN5G(5680, 31), /* Channel 136 */
-       CHAN5G(5700, 32), /* Channel 140 */
-       /* _We_ call this UNII 3 */
-       CHAN5G(5745, 33), /* Channel 149 */
-       CHAN5G(5765, 34), /* Channel 153 */
-       CHAN5G(5785, 35), /* Channel 157 */
-       CHAN5G(5805, 36), /* Channel 161 */
-       CHAN5G(5825, 37), /* Channel 165 */
-};
-
-/* Atheros hardware rate code addition for short premble */
-#define SHPCHECK(__hw_rate, __flags) \
-       ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
-
-#define RATE(_bitrate, _hw_rate, _flags) {              \
-       .bitrate        = (_bitrate),                   \
-       .flags          = (_flags),                     \
-       .hw_value       = (_hw_rate),                   \
-       .hw_value_short = (SHPCHECK(_hw_rate, _flags))  \
-}
-
-static struct ieee80211_rate ath9k_legacy_rates[] = {
-       RATE(10, 0x1b, 0),
-       RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
-       RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
-       RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
-       RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ |
-                       IEEE80211_RATE_SUPPORTS_10MHZ)),
-       RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ |
-                       IEEE80211_RATE_SUPPORTS_10MHZ)),
-       RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ |
-                        IEEE80211_RATE_SUPPORTS_10MHZ)),
-       RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ |
-                        IEEE80211_RATE_SUPPORTS_10MHZ)),
-       RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ |
-                        IEEE80211_RATE_SUPPORTS_10MHZ)),
-       RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ |
-                        IEEE80211_RATE_SUPPORTS_10MHZ)),
-       RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ |
-                        IEEE80211_RATE_SUPPORTS_10MHZ)),
-       RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ |
-                        IEEE80211_RATE_SUPPORTS_10MHZ)),
-};
 
 #ifdef CONFIG_MAC80211_LEDS
 static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = {
@@ -258,64 +153,6 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl
 /*     Initialization     */
 /**************************/
 
-static void setup_ht_cap(struct ath_softc *sc,
-                        struct ieee80211_sta_ht_cap *ht_info)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       u8 tx_streams, rx_streams;
-       int i, max_streams;
-
-       ht_info->ht_supported = true;
-       ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
-                      IEEE80211_HT_CAP_SM_PS |
-                      IEEE80211_HT_CAP_SGI_40 |
-                      IEEE80211_HT_CAP_DSSSCCK40;
-
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
-               ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
-
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
-               ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
-
-       ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
-       ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
-
-       if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah))
-               max_streams = 1;
-       else if (AR_SREV_9462(ah))
-               max_streams = 2;
-       else if (AR_SREV_9300_20_OR_LATER(ah))
-               max_streams = 3;
-       else
-               max_streams = 2;
-
-       if (AR_SREV_9280_20_OR_LATER(ah)) {
-               if (max_streams >= 2)
-                       ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
-               ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
-       }
-
-       /* set up supported mcs set */
-       memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-       tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams);
-       rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams);
-
-       ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
-               tx_streams, rx_streams);
-
-       if (tx_streams != rx_streams) {
-               ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
-               ht_info->mcs.tx_params |= ((tx_streams - 1) <<
-                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
-       }
-
-       for (i = 0; i < rx_streams; i++)
-               ht_info->mcs.rx_mask[i] = 0xff;
-
-       ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
-}
-
 static void ath9k_reg_notifier(struct wiphy *wiphy,
                               struct regulatory_request *request)
 {
@@ -486,51 +323,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
        return 0;
 }
 
-static int ath9k_init_channels_rates(struct ath_softc *sc)
-{
-       void *channels;
-
-       BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
-                    ARRAY_SIZE(ath9k_5ghz_chantable) !=
-                    ATH9K_NUM_CHANNELS);
-
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
-               channels = devm_kzalloc(sc->dev,
-                       sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
-               if (!channels)
-                   return -ENOMEM;
-
-               memcpy(channels, ath9k_2ghz_chantable,
-                      sizeof(ath9k_2ghz_chantable));
-               sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
-               sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
-               sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
-                       ARRAY_SIZE(ath9k_2ghz_chantable);
-               sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
-               sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
-                       ARRAY_SIZE(ath9k_legacy_rates);
-       }
-
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
-               channels = devm_kzalloc(sc->dev,
-                       sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
-               if (!channels)
-                       return -ENOMEM;
-
-               memcpy(channels, ath9k_5ghz_chantable,
-                      sizeof(ath9k_5ghz_chantable));
-               sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
-               sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
-               sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
-                       ARRAY_SIZE(ath9k_5ghz_chantable);
-               sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
-                       ath9k_legacy_rates + 4;
-               sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
-                       ARRAY_SIZE(ath9k_legacy_rates) - 4;
-       }
-       return 0;
-}
-
 static void ath9k_init_misc(struct ath_softc *sc)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -793,7 +585,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        if (ret)
                goto err_btcoex;
 
-       ret = ath9k_init_channels_rates(sc);
+       ret = ath9k_cmn_init_channels_rates(common);
        if (ret)
                goto err_btcoex;
 
@@ -823,10 +615,11 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *chan;
        struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct cfg80211_chan_def chandef;
        int i;
 
-       sband = &sc->sbands[band];
+       sband = &common->sbands[band];
        for (i = 0; i < sband->n_channels; i++) {
                chan = &sband->channels[i];
                ah->curchan = &ah->channels[chan->hw_value];
@@ -849,17 +642,6 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc)
        ah->curchan = curchan;
 }
 
-void ath9k_reload_chainmask_settings(struct ath_softc *sc)
-{
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT))
-               return;
-
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
-               setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
-               setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
-}
-
 static const struct ieee80211_iface_limit if_limits[] = {
        { .max = 2048,  .types = BIT(NL80211_IFTYPE_STATION) |
                                 BIT(NL80211_IFTYPE_P2P_CLIENT) |
@@ -949,6 +731,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
        hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
        hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
        hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+       hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
 
        hw->queues = 4;
        hw->max_rates = 4;
@@ -969,13 +752,13 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
                hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-                       &sc->sbands[IEEE80211_BAND_2GHZ];
+                       &common->sbands[IEEE80211_BAND_2GHZ];
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
                hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       &sc->sbands[IEEE80211_BAND_5GHZ];
+                       &common->sbands[IEEE80211_BAND_5GHZ];
 
        ath9k_init_wow(hw);
-       ath9k_reload_chainmask_settings(sc);
+       ath9k_cmn_reload_chainmask(ah);
 
        SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
 }
index afce549a097bc4b7ec3ebd87fecb490e82a85bed..42a18037004e5463711db4243de3a6ad1eb7b0c2 100644 (file)
@@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data)
                 * interrupts are enabled in the reset routine.
                 */
                atomic_inc(&ah->intr_ref_cnt);
-               ath_dbg(common, ANY, "FATAL: Skipping interrupts\n");
+               ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
                goto out;
        }
 
@@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data)
                         * interrupts are enabled in the reset routine.
                         */
                        atomic_inc(&ah->intr_ref_cnt);
-                       ath_dbg(common, ANY,
+                       ath_dbg(common, RESET,
                                "BB_WATCHDOG: Skipping interrupts\n");
                        goto out;
                }
@@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data)
                        type = RESET_TYPE_TX_GTT;
                        ath9k_queue_reset(sc, type);
                        atomic_inc(&ah->intr_ref_cnt);
-                       ath_dbg(common, ANY,
+                       ath_dbg(common, RESET,
                                "GTT: Skipping interrupts\n");
                        goto out;
                }
@@ -2053,7 +2053,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
                ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
 
        ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
-       ath9k_reload_chainmask_settings(sc);
+       ath9k_cmn_reload_chainmask(ah);
 
        return 0;
 }
index 076dae1e5ab7f6de22bfdf5c179b6bd4bb09ba1b..6c9accdb52e4140076d7378f530e975c34f68433 100644 (file)
@@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc,
                        return NULL;
 
                /*
-                * mark descriptor as zero-length and set the 'more'
-                * flag to ensure that both buffers get discarded
+                * Re-check previous descriptor, in case it has been filled
+                * in the mean time.
                 */
-               rs->rs_datalen = 0;
-               rs->rs_more = true;
+               ret = ath9k_hw_rxprocdesc(ah, ds, rs);
+               if (ret == -EINPROGRESS) {
+                       /*
+                        * mark descriptor as zero-length and set the 'more'
+                        * flag to ensure that both buffers get discarded
+                        */
+                       rs->rs_datalen = 0;
+                       rs->rs_more = true;
+               }
        }
 
        list_del(&bf->list);
@@ -787,32 +794,32 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
        struct ath_common *common = ath9k_hw_common(ah);
        struct ieee80211_hdr *hdr;
        bool discard_current = sc->rx.discard_next;
-       int ret = 0;
 
        /*
         * Discard corrupt descriptors which are marked in
         * ath_get_next_rx_buf().
         */
-       sc->rx.discard_next = rx_stats->rs_more;
        if (discard_current)
-               return -EINVAL;
+               goto corrupt;
+
+       sc->rx.discard_next = false;
 
        /*
         * Discard zero-length packets.
         */
        if (!rx_stats->rs_datalen) {
                RX_STAT_INC(rx_len_err);
-               return -EINVAL;
+               goto corrupt;
        }
 
-        /*
-         * rs_status follows rs_datalen so if rs_datalen is too large
-         * we can take a hint that hardware corrupted it, so ignore
-         * those frames.
-         */
+       /*
+        * rs_status follows rs_datalen so if rs_datalen is too large
+        * we can take a hint that hardware corrupted it, so ignore
+        * those frames.
+        */
        if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {
                RX_STAT_INC(rx_len_err);
-               return -EINVAL;
+               goto corrupt;
        }
 
        /* Only use status info from the last fragment */
@@ -826,10 +833,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
         * This is different from the other corrupt descriptor
         * condition handled above.
         */
-       if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) {
-               ret = -EINVAL;
-               goto exit;
-       }
+       if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC)
+               goto corrupt;
 
        hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
 
@@ -845,18 +850,15 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
                if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
                        RX_STAT_INC(rx_spectral);
 
-               ret = -EINVAL;
-               goto exit;
+               return -EINVAL;
        }
 
        /*
         * everything but the rate is checked here, the rate check is done
         * separately to avoid doing two lookups for a rate for each frame.
         */
-       if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter)) {
-               ret = -EINVAL;
-               goto exit;
-       }
+       if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter))
+               return -EINVAL;
 
        if (ath_is_mybeacon(common, hdr)) {
                RX_STAT_INC(rx_beacons);
@@ -866,10 +868,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
        /*
         * This shouldn't happen, but have a safety check anyway.
         */
-       if (WARN_ON(!ah->curchan)) {
-               ret = -EINVAL;
-               goto exit;
-       }
+       if (WARN_ON(!ah->curchan))
+               return -EINVAL;
 
        if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) {
                /*
@@ -879,8 +879,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
                ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
                        rx_stats->rs_rate);
                RX_STAT_INC(rx_rate_err);
-               ret =-EINVAL;
-               goto exit;
+               return -EINVAL;
        }
 
        ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
@@ -896,9 +895,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
                sc->rx.num_pkts++;
 #endif
 
-exit:
-       sc->rx.discard_next = false;
-       return ret;
+       return 0;
+
+corrupt:
+       sc->rx.discard_next = rx_stats->rs_more;
+       return -EINVAL;
 }
 
 /*
index a6507046dfe8e3fc1198ecec5ace1e0f8c60fdbc..fafacfed44eab0f634fca792c978295faf72ec4d 100644 (file)
@@ -1040,11 +1040,11 @@ static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi)
        int symbols, bits;
        int bytes = 0;
 
+       usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
        symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec);
        bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams;
        bits -= OFDM_PLCP_BITS;
        bytes = bits / 8;
-       bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
        if (bytes > 65532)
                bytes = 65532;
 
@@ -1076,6 +1076,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
                             struct ath_tx_info *info, int len, bool rts)
 {
        struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct sk_buff *skb;
        struct ieee80211_tx_info *tx_info;
        struct ieee80211_tx_rate *rates;
@@ -1145,7 +1146,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
                }
 
                /* legacy rates */
-               rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
+               rate = &common->sbands[tx_info->band].bitrates[rates[i].idx];
                if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
                    !(rate->flags & IEEE80211_RATE_ERP_G))
                        phy = WLAN_RC_PHY_CCK;
@@ -1444,14 +1445,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
        for (tidno = 0, tid = &an->tid[tidno];
             tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
 
-               if (!tid->sched)
-                       continue;
-
                ac = tid->ac;
                txq = ac->txq;
 
                ath_txq_lock(sc, txq);
 
+               if (!tid->sched) {
+                       ath_txq_unlock(sc, txq);
+                       continue;
+               }
+
                buffered = ath_tid_has_buffered(tid);
 
                tid->sched = false;
@@ -2184,14 +2187,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                txq->stopped = true;
        }
 
+       if (txctl->an)
+               tid = ath_get_skb_tid(sc, txctl->an, skb);
+
        if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
                ath_txq_unlock(sc, txq);
                txq = sc->tx.uapsdq;
                ath_txq_lock(sc, txq);
        } else if (txctl->an &&
                   ieee80211_is_data_present(hdr->frame_control)) {
-               tid = ath_get_skb_tid(sc, txctl->an, skb);
-
                WARN_ON(tid->ac->txq != txctl->txq);
 
                if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
index e5e905910db49c569c8287de38141fc4a4b3d244..415393dfb6fc17b51d33f4d24e70c6700620d4b5 100644 (file)
@@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
 static const struct
 ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
 {
-       switch (reg->regpair->regDmnEnum) {
+       switch (reg->regpair->reg_domain) {
        case 0x60:
        case 0x61:
        case 0x62:
@@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
                                      enum nl80211_reg_initiator initiator,
                                      struct ath_regulatory *reg)
 {
-       switch (reg->regpair->regDmnEnum) {
+       switch (reg->regpair->reg_domain) {
        case 0x60:
        case 0x63:
        case 0x66:
@@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
                        printk(KERN_DEBUG "ath: EEPROM indicates we "
                               "should expect a direct regpair map\n");
                for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
-                       if (regDomainPairs[i].regDmnEnum == rd)
+                       if (regDomainPairs[i].reg_domain == rd)
                                return true;
        }
        printk(KERN_DEBUG
@@ -617,7 +617,7 @@ ath_get_regpair(int regdmn)
        if (regdmn == NO_ENUMRD)
                return NULL;
        for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
-               if (regDomainPairs[i].regDmnEnum == regdmn)
+               if (regDomainPairs[i].reg_domain == regdmn)
                        return &regDomainPairs[i];
        }
        return NULL;
@@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
        printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
                reg->alpha2[0], reg->alpha2[1]);
        printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
-               reg->regpair->regDmnEnum);
+               reg->regpair->reg_domain);
 
        return 0;
 }
index 990dd42ae79ed312652a336f46fc1ab4c9ad7ad8..c7a3465fd02ad3b6942fd43bb1aa88bf4bc0e44f 100644 (file)
@@ -9,6 +9,7 @@ wil6210-y += wmi.o
 wil6210-y += interrupt.o
 wil6210-y += txrx.o
 wil6210-y += debug.o
+wil6210-y += rx_reorder.o
 wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
 
 # for tracing framework to find trace.h
index 5b340769d5bb2196bf3d0192e007ed13f23236fc..74393035706168e3cae5eebf7ed3f9561c928b35 100644 (file)
@@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)
        return -EOPNOTSUPP;
 }
 
-static int wil_cfg80211_get_station(struct wiphy *wiphy,
-                                   struct net_device *ndev,
-                                   u8 *mac, struct station_info *sinfo)
+static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
+                             struct station_info *sinfo)
 {
-       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-       int rc;
        struct wmi_notify_req_cmd cmd = {
-               .cid = 0,
+               .cid = cid,
                .interval_usec = 0,
        };
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_notify_req_done_event evt;
+       } __packed reply;
+       struct wil_net_stats *stats = &wil->sta[cid].stats;
+       int rc;
 
-       if (memcmp(mac, wil->dst_addr[0], ETH_ALEN))
-               return -ENOENT;
-
-       /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
        rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
-                     WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20);
+                     WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
        if (rc)
                return rc;
 
+       wil_dbg_wmi(wil, "Link status for CID %d: {\n"
+                   "  MCS %d TSF 0x%016llx\n"
+                   "  BF status 0x%08x SNR 0x%08x SQI %d%%\n"
+                   "  Tx Tpt %d goodput %d Rx goodput %d\n"
+                   "  Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
+                   cid, le16_to_cpu(reply.evt.bf_mcs),
+                   le64_to_cpu(reply.evt.tsf), reply.evt.status,
+                   le32_to_cpu(reply.evt.snr_val),
+                   reply.evt.sqi,
+                   le32_to_cpu(reply.evt.tx_tpt),
+                   le32_to_cpu(reply.evt.tx_goodput),
+                   le32_to_cpu(reply.evt.rx_goodput),
+                   le16_to_cpu(reply.evt.my_rx_sector),
+                   le16_to_cpu(reply.evt.my_tx_sector),
+                   le16_to_cpu(reply.evt.other_rx_sector),
+                   le16_to_cpu(reply.evt.other_tx_sector));
+
        sinfo->generation = wil->sinfo_gen;
 
-       sinfo->filled |= STATION_INFO_TX_BITRATE;
+       sinfo->filled = STATION_INFO_RX_BYTES |
+                       STATION_INFO_TX_BYTES |
+                       STATION_INFO_RX_PACKETS |
+                       STATION_INFO_TX_PACKETS |
+                       STATION_INFO_RX_BITRATE |
+                       STATION_INFO_TX_BITRATE |
+                       STATION_INFO_RX_DROP_MISC |
+                       STATION_INFO_TX_FAILED;
+
        sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
-       sinfo->txrate.mcs = wil->stats.bf_mcs;
-       sinfo->filled |= STATION_INFO_RX_BITRATE;
+       sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
        sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
-       sinfo->rxrate.mcs = wil->stats.last_mcs_rx;
+       sinfo->rxrate.mcs = stats->last_mcs_rx;
+       sinfo->rx_bytes = stats->rx_bytes;
+       sinfo->rx_packets = stats->rx_packets;
+       sinfo->rx_dropped_misc = stats->rx_dropped;
+       sinfo->tx_bytes = stats->tx_bytes;
+       sinfo->tx_packets = stats->tx_packets;
+       sinfo->tx_failed = stats->tx_errors;
 
        if (test_bit(wil_status_fwconnected, &wil->status)) {
                sinfo->filled |= STATION_INFO_SIGNAL;
-               sinfo->signal = 12; /* TODO: provide real value */
+               sinfo->signal = reply.evt.sqi;
        }
 
-       return 0;
+       return rc;
+}
+
+static int wil_cfg80211_get_station(struct wiphy *wiphy,
+                                   struct net_device *ndev,
+                                   u8 *mac, struct station_info *sinfo)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       int rc;
+
+       int cid = wil_find_cid(wil, mac);
+
+       wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
+       if (cid < 0)
+               return cid;
+
+       rc = wil_cid_fill_sinfo(wil, cid, sinfo);
+
+       return rc;
+}
+
+/*
+ * Find @idx-th active STA for station dump.
+ */
+static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+               if (wil->sta[i].status == wil_sta_unused)
+                       continue;
+               if (idx == 0)
+                       return i;
+               idx--;
+       }
+
+       return -ENOENT;
+}
+
+static int wil_cfg80211_dump_station(struct wiphy *wiphy,
+                                    struct net_device *dev, int idx,
+                                    u8 *mac, struct station_info *sinfo)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       int rc;
+       int cid = wil_find_cid_by_idx(wil, idx);
+
+       if (cid < 0)
+               return -ENOENT;
+
+       memcpy(mac, wil->sta[cid].addr, ETH_ALEN);
+       wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
+
+       rc = wil_cid_fill_sinfo(wil, cid, sinfo);
+
+       return rc;
 }
 
 static int wil_cfg80211_change_iface(struct wiphy *wiphy,
@@ -352,6 +436,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
        return rc;
 }
 
+static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy,
+                               struct wireless_dev *wdev,
+                               struct cfg80211_mgmt_tx_params *params,
+                               u64 *cookie)
+{
+       const u8 *buf = params->buf;
+       size_t len = params->len;
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       int rc;
+       struct ieee80211_mgmt *mgmt_frame = (void *)buf;
+       struct wmi_sw_tx_req_cmd *cmd;
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_sw_tx_complete_event evt;
+       } __packed evt;
+
+       cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
+       cmd->len = cpu_to_le16(len);
+       memcpy(cmd->payload, buf, len);
+
+       rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
+                     WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
+       if (rc == 0)
+               rc = evt.evt.status;
+
+       kfree(cmd);
+
+       return rc;
+}
+
 static int wil_cfg80211_set_channel(struct wiphy *wiphy,
                                    struct cfg80211_chan_def *chandef)
 {
@@ -402,6 +520,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
        return 0;
 }
 
+static int wil_remain_on_channel(struct wiphy *wiphy,
+                                struct wireless_dev *wdev,
+                                struct ieee80211_channel *chan,
+                                unsigned int duration,
+                                u64 *cookie)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       int rc;
+
+       /* TODO: handle duration */
+       wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration);
+
+       rc = wmi_set_channel(wil, chan->hw_value);
+       if (rc)
+               return rc;
+
+       rc = wmi_rxon(wil, true);
+
+       return rc;
+}
+
+static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
+                                       struct wireless_dev *wdev,
+                                       u64 cookie)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       int rc;
+
+       wil_info(wil, "%s()\n", __func__);
+
+       rc = wmi_rxon(wil, false);
+
+       return rc;
+}
+
 static int wil_fix_bcon(struct wil6210_priv *wil,
                        struct cfg80211_beacon_data *bcon)
 {
@@ -504,12 +657,24 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
        return rc;
 }
 
+static int wil_cfg80211_del_station(struct wiphy *wiphy,
+                                   struct net_device *dev, u8 *mac)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       wil6210_disconnect(wil, mac);
+       return 0;
+}
+
 static struct cfg80211_ops wil_cfg80211_ops = {
        .scan = wil_cfg80211_scan,
        .connect = wil_cfg80211_connect,
        .disconnect = wil_cfg80211_disconnect,
        .change_virtual_intf = wil_cfg80211_change_iface,
        .get_station = wil_cfg80211_get_station,
+       .dump_station = wil_cfg80211_dump_station,
+       .remain_on_channel = wil_remain_on_channel,
+       .cancel_remain_on_channel = wil_cancel_remain_on_channel,
+       .mgmt_tx = wil_cfg80211_mgmt_tx,
        .set_monitor_channel = wil_cfg80211_set_channel,
        .add_key = wil_cfg80211_add_key,
        .del_key = wil_cfg80211_del_key,
@@ -517,6 +682,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
        /* AP mode */
        .start_ap = wil_cfg80211_start_ap,
        .stop_ap = wil_cfg80211_stop_ap,
+       .del_station = wil_cfg80211_del_station,
 };
 
 static void wil_wiphy_init(struct wiphy *wiphy)
@@ -542,7 +708,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
        wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;
 
        /* TODO: figure this out */
-       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
 
        wiphy->cipher_suites = wil_cipher_suites;
        wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
index 1caa31992a7e1ecc25b03d32d78aaf12894fcd78..1d09a4b0a0f45fee3c8aeebc493870d86501628c 100644 (file)
 /* Nasty hack. Better have per device instances */
 static u32 mem_addr;
 static u32 dbg_txdesc_index;
+static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
 
 static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
-                           const char *name, struct vring *vring)
+                           const char *name, struct vring *vring,
+                           char _s, char _h)
 {
        void __iomem *x = wmi_addr(wil, vring->hwtail);
 
@@ -50,8 +52,8 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
                        volatile struct vring_tx_desc *d = &vring->va[i].tx;
                        if ((i % 64) == 0 && (i != 0))
                                seq_printf(s, "\n");
-                       seq_printf(s, "%s", (d->dma.status & BIT(0)) ?
-                                       "S" : (vring->ctx[i].skb ? "H" : "h"));
+                       seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
+                                       _s : (vring->ctx[i].skb ? _h : 'h'));
                }
                seq_printf(s, "\n");
        }
@@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
        uint i;
        struct wil6210_priv *wil = s->private;
 
-       wil_print_vring(s, wil, "rx", &wil->vring_rx);
+       wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
 
        for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
                struct vring *vring = &(wil->vring_tx[i]);
                if (vring->va) {
+                       int cid = wil->vring2cid_tid[i][0];
+                       int tid = wil->vring2cid_tid[i][1];
                        char name[10];
                        snprintf(name, sizeof(name), "tx_%2d", i);
-                       wil_print_vring(s, wil, name, vring);
+
+                       seq_printf(s, "\n%pM CID %d TID %d\n",
+                                  wil->sta[cid].addr, cid, tid);
+                       wil_print_vring(s, wil, name, vring, '_', 'H');
                }
        }
 
@@ -390,25 +397,40 @@ static const struct file_operations fops_reset = {
        .write = wil_write_file_reset,
        .open  = simple_open,
 };
-/*---------Tx descriptor------------*/
 
+/*---------Tx/Rx descriptor------------*/
 static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
 {
        struct wil6210_priv *wil = s->private;
-       struct vring *vring = &(wil->vring_tx[0]);
+       struct vring *vring;
+       bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
+       if (tx)
+               vring = &(wil->vring_tx[dbg_vring_index]);
+       else
+               vring = &wil->vring_rx;
 
        if (!vring->va) {
-               seq_printf(s, "No Tx VRING\n");
+               if (tx)
+                       seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index);
+               else
+                       seq_puts(s, "No Rx VRING\n");
                return 0;
        }
 
        if (dbg_txdesc_index < vring->size) {
+               /* use struct vring_tx_desc for Rx as well,
+                * only field used, .dma.length, is the same
+                */
                volatile struct vring_tx_desc *d =
                                &(vring->va[dbg_txdesc_index].tx);
                volatile u32 *u = (volatile u32 *)d;
                struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
 
-               seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index);
+               if (tx)
+                       seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index,
+                                  dbg_txdesc_index);
+               else
+                       seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);
                seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
                           u[0], u[1], u[2], u[3]);
                seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
@@ -439,8 +461,13 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
                }
                seq_printf(s, "}\n");
        } else {
-               seq_printf(s, "TxDesc index (%d) >= size (%d)\n",
-                          dbg_txdesc_index, vring->size);
+               if (tx)
+                       seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
+                                  dbg_vring_index, dbg_txdesc_index,
+                                  vring->size);
+               else
+                       seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
+                                  dbg_txdesc_index, vring->size);
        }
 
        return 0;
@@ -570,6 +597,68 @@ static const struct file_operations fops_temp = {
        .llseek         = seq_lseek,
 };
 
+/*---------Station matrix------------*/
+static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
+{
+       int i;
+       u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
+       seq_printf(s, "0x%03x [", r->head_seq_num);
+       for (i = 0; i < r->buf_size; i++) {
+               if (i == index)
+                       seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
+               else
+                       seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
+       }
+       seq_puts(s, "]\n");
+}
+
+static int wil_sta_debugfs_show(struct seq_file *s, void *data)
+{
+       struct wil6210_priv *wil = s->private;
+       int i, tid;
+
+       for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+               struct wil_sta_info *p = &wil->sta[i];
+               char *status = "unknown";
+               switch (p->status) {
+               case wil_sta_unused:
+                       status = "unused   ";
+                       break;
+               case wil_sta_conn_pending:
+                       status = "pending  ";
+                       break;
+               case wil_sta_connected:
+                       status = "connected";
+                       break;
+               }
+               seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
+
+               if (p->status == wil_sta_connected) {
+                       for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
+                               struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
+                               if (r) {
+                                       seq_printf(s, "[%2d] ", tid);
+                                       wil_print_rxtid(s, r);
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int wil_sta_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, wil_sta_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_sta = {
+       .open           = wil_sta_seq_open,
+       .release        = single_release,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+};
+
 /*----------------*/
 int wil6210_debugfs_init(struct wil6210_priv *wil)
 {
@@ -581,9 +670,13 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
 
        debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
        debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
-       debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc);
-       debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg,
+       debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
+       debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
+       debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
                           &dbg_txdesc_index);
+       debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg,
+                          &dbg_vring_index);
+
        debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
        debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
        debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
index fd30cddd58821f9c602a3bba0fcb91bbfc88aeef..41c362dee0329a5934df1f39c8ecb06d808fded3 100644 (file)
 
 #include <linux/moduleparam.h>
 #include <linux/if_arp.h>
+#include <linux/etherdevice.h>
 
 #include "wil6210.h"
+#include "txrx.h"
 
 /*
  * Due to a hardware issue,
@@ -52,29 +54,75 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
                __raw_writel(*s++, d++);
 }
 
-static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
+static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
 {
        uint i;
-       struct net_device *ndev = wil_to_ndev(wil);
+       struct wil_sta_info *sta = &wil->sta[cid];
 
-       wil_dbg_misc(wil, "%s()\n", __func__);
+       if (sta->status != wil_sta_unused) {
+               wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
+               sta->status = wil_sta_unused;
+       }
+
+       for (i = 0; i < WIL_STA_TID_NUM; i++) {
+               struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+               sta->tid_rx[i] = NULL;
+               wil_tid_ampdu_rx_free(wil, r);
+       }
+       for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
+               if (wil->vring2cid_tid[i][0] == cid)
+                       wil_vring_fini_tx(wil, i);
+       }
+       memset(&sta->stats, 0, sizeof(sta->stats));
+}
+
+static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
+{
+       int cid = -ENOENT;
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wireless_dev *wdev = wil->wdev;
 
-       wil_link_off(wil);
-       if (test_bit(wil_status_fwconnected, &wil->status)) {
-               clear_bit(wil_status_fwconnected, &wil->status);
-               cfg80211_disconnected(ndev,
-                                     WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                     NULL, 0, GFP_KERNEL);
-       } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
-               cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
-                                       WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                       GFP_KERNEL);
+       might_sleep();
+       if (bssid) {
+               cid = wil_find_cid(wil, bssid);
+               wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
+       } else {
+               wil_dbg_misc(wil, "%s(all)\n", __func__);
        }
-       clear_bit(wil_status_fwconnecting, &wil->status);
-       for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
-               wil_vring_fini_tx(wil, i);
 
-       clear_bit(wil_status_dontscan, &wil->status);
+       if (cid >= 0) /* disconnect 1 peer */
+               wil_disconnect_cid(wil, cid);
+       else /* disconnect all */
+               for (cid = 0; cid < WIL6210_MAX_CID; cid++)
+                       wil_disconnect_cid(wil, cid);
+
+       /* link state */
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
+               wil_link_off(wil);
+               if (test_bit(wil_status_fwconnected, &wil->status)) {
+                       clear_bit(wil_status_fwconnected, &wil->status);
+                       cfg80211_disconnected(ndev,
+                                             WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                             NULL, 0, GFP_KERNEL);
+               } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
+                       cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
+                                               WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                               GFP_KERNEL);
+               }
+               clear_bit(wil_status_fwconnecting, &wil->status);
+               wil_dbg_misc(wil, "clear_bit(wil_status_dontscan)\n");
+               clear_bit(wil_status_dontscan, &wil->status);
+               break;
+       default:
+               /* AP-like interface and monitor:
+                * never scan, always connected
+                */
+               if (bssid)
+                       cfg80211_del_sta(ndev, bssid, GFP_KERNEL);
+               break;
+       }
 }
 
 static void wil_disconnect_worker(struct work_struct *work)
@@ -97,12 +145,23 @@ static void wil_connect_timer_fn(ulong x)
        schedule_work(&wil->disconnect_worker);
 }
 
+static int wil_find_free_vring(struct wil6210_priv *wil)
+{
+       int i;
+       for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+               if (!wil->vring_tx[i].va)
+                       return i;
+       }
+       return -EINVAL;
+}
+
 static void wil_connect_worker(struct work_struct *work)
 {
        int rc;
        struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
                                                connect_worker);
        int cid = wil->pending_connect_cid;
+       int ringid = wil_find_free_vring(wil);
 
        if (cid < 0) {
                wil_err(wil, "No connection pending\n");
@@ -111,16 +170,22 @@ static void wil_connect_worker(struct work_struct *work)
 
        wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
 
-       rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0);
+       rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);
        wil->pending_connect_cid = -1;
-       if (rc == 0)
+       if (rc == 0) {
+               wil->sta[cid].status = wil_sta_connected;
                wil_link_on(wil);
+       } else {
+               wil->sta[cid].status = wil_sta_unused;
+       }
 }
 
 int wil_priv_init(struct wil6210_priv *wil)
 {
        wil_dbg_misc(wil, "%s()\n", __func__);
 
+       memset(wil->sta, 0, sizeof(wil->sta));
+
        mutex_init(&wil->mutex);
        mutex_init(&wil->wmi_mutex);
 
@@ -370,3 +435,19 @@ int wil_down(struct wil6210_priv *wil)
 
        return rc;
 }
+
+int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
+{
+       int i;
+       int rc = -ENOENT;
+
+       for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+               if ((wil->sta[i].status != wil_sta_unused) &&
+                   ether_addr_equal(wil->sta[i].addr, mac)) {
+                       rc = i;
+                       break;
+               }
+       }
+
+       return rc;
+}
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
new file mode 100644 (file)
index 0000000..d04629f
--- /dev/null
@@ -0,0 +1,177 @@
+#include "wil6210.h"
+#include "txrx.h"
+
+#define SEQ_MODULO 0x1000
+#define SEQ_MASK   0xfff
+
+static inline int seq_less(u16 sq1, u16 sq2)
+{
+       return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
+}
+
+static inline u16 seq_inc(u16 sq)
+{
+       return (sq + 1) & SEQ_MASK;
+}
+
+static inline u16 seq_sub(u16 sq1, u16 sq2)
+{
+       return (sq1 - sq2) & SEQ_MASK;
+}
+
+static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq)
+{
+       return seq_sub(seq, r->ssn) % r->buf_size;
+}
+
+static void wil_release_reorder_frame(struct wil6210_priv *wil,
+                                     struct wil_tid_ampdu_rx *r,
+                                     int index)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct sk_buff *skb = r->reorder_buf[index];
+
+       if (!skb)
+               goto no_frame;
+
+       /* release the frame from the reorder ring buffer */
+       r->stored_mpdu_num--;
+       r->reorder_buf[index] = NULL;
+       wil_netif_rx_any(skb, ndev);
+
+no_frame:
+       r->head_seq_num = seq_inc(r->head_seq_num);
+}
+
+static void wil_release_reorder_frames(struct wil6210_priv *wil,
+                                      struct wil_tid_ampdu_rx *r,
+                                      u16 hseq)
+{
+       int index;
+
+       while (seq_less(r->head_seq_num, hseq)) {
+               index = reorder_index(r, r->head_seq_num);
+               wil_release_reorder_frame(wil, r, index);
+       }
+}
+
+static void wil_reorder_release(struct wil6210_priv *wil,
+                               struct wil_tid_ampdu_rx *r)
+{
+       int index = reorder_index(r, r->head_seq_num);
+
+       while (r->reorder_buf[index]) {
+               wil_release_reorder_frame(wil, r, index);
+               index = reorder_index(r, r->head_seq_num);
+       }
+}
+
+void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct vring_rx_desc *d = wil_skb_rxdesc(skb);
+       int tid = wil_rxdesc_tid(d);
+       int cid = wil_rxdesc_cid(d);
+       int mid = wil_rxdesc_mid(d);
+       u16 seq = wil_rxdesc_seq(d);
+       struct wil_sta_info *sta = &wil->sta[cid];
+       struct wil_tid_ampdu_rx *r = sta->tid_rx[tid];
+       u16 hseq;
+       int index;
+
+       wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
+                    mid, cid, tid, seq);
+
+       if (!r) {
+               wil_netif_rx_any(skb, ndev);
+               return;
+       }
+
+       hseq = r->head_seq_num;
+
+       spin_lock(&r->reorder_lock);
+
+       /* frame with out of date sequence number */
+       if (seq_less(seq, r->head_seq_num)) {
+               dev_kfree_skb(skb);
+               goto out;
+       }
+
+       /*
+        * If frame the sequence number exceeds our buffering window
+        * size release some previous frames to make room for this one.
+        */
+       if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
+               hseq = seq_inc(seq_sub(seq, r->buf_size));
+               /* release stored frames up to new head to stack */
+               wil_release_reorder_frames(wil, r, hseq);
+       }
+
+       /* Now the new frame is always in the range of the reordering buffer */
+
+       index = reorder_index(r, seq);
+
+       /* check if we already stored this frame */
+       if (r->reorder_buf[index]) {
+               dev_kfree_skb(skb);
+               goto out;
+       }
+
+       /*
+        * If the current MPDU is in the right order and nothing else
+        * is stored we can process it directly, no need to buffer it.
+        * If it is first but there's something stored, we may be able
+        * to release frames after this one.
+        */
+       if (seq == r->head_seq_num && r->stored_mpdu_num == 0) {
+               r->head_seq_num = seq_inc(r->head_seq_num);
+               wil_netif_rx_any(skb, ndev);
+               goto out;
+       }
+
+       /* put the frame in the reordering buffer */
+       r->reorder_buf[index] = skb;
+       r->reorder_time[index] = jiffies;
+       r->stored_mpdu_num++;
+       wil_reorder_release(wil, r);
+
+out:
+       spin_unlock(&r->reorder_lock);
+}
+
+struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
+                                               int size, u16 ssn)
+{
+       struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
+       if (!r)
+               return NULL;
+
+       r->reorder_buf =
+               kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL);
+       r->reorder_time =
+               kcalloc(size, sizeof(unsigned long), GFP_KERNEL);
+       if (!r->reorder_buf || !r->reorder_time) {
+               kfree(r->reorder_buf);
+               kfree(r->reorder_time);
+               kfree(r);
+               return NULL;
+       }
+
+       spin_lock_init(&r->reorder_lock);
+       r->ssn = ssn;
+       r->head_seq_num = ssn;
+       r->buf_size = size;
+       r->stored_mpdu_num = 0;
+       return r;
+}
+
+void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
+                          struct wil_tid_ampdu_rx *r)
+{
+       if (!r)
+               return;
+       wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size);
+       kfree(r->reorder_buf);
+       kfree(r->reorder_time);
+       kfree(r);
+}
index 0b0975d88b431644f172514442eea9dd272a1d38..092081e209dab5f863bf34e24f4721bf9e014d27 100644 (file)
@@ -344,6 +344,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        u16 dmalen;
        u8 ftype;
        u8 ds_bits;
+       int cid;
+       struct wil_net_stats *stats;
+
 
        BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
 
@@ -383,8 +386,10 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
                          skb->data, skb_headlen(skb), false);
 
-
-       wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
+       cid = wil_rxdesc_cid(d);
+       stats = &wil->sta[cid].stats;
+       stats->last_mcs_rx = wil_rxdesc_mcs(d);
+       wil->stats.last_mcs_rx = stats->last_mcs_rx;
 
        /* use radiotap header only if required */
        if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
@@ -472,10 +477,14 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
  * Pass Rx packet to the netif. Update statistics.
  * Called in softirq context (NAPI poll).
  */
-static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
+void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
 {
        int rc;
+       struct wil6210_priv *wil = ndev_to_wil(ndev);
        unsigned int len = skb->len;
+       struct vring_rx_desc *d = wil_skb_rxdesc(skb);
+       int cid = wil_rxdesc_cid(d);
+       struct wil_net_stats *stats = &wil->sta[cid].stats;
 
        skb_orphan(skb);
 
@@ -483,10 +492,13 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
 
        if (likely(rc == NET_RX_SUCCESS)) {
                ndev->stats.rx_packets++;
+               stats->rx_packets++;
                ndev->stats.rx_bytes += len;
+               stats->rx_bytes += len;
 
        } else {
                ndev->stats.rx_dropped++;
+               stats->rx_dropped++;
        }
 }
 
@@ -515,12 +527,18 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                        skb->pkt_type = PACKET_OTHERHOST;
                        skb->protocol = htons(ETH_P_802_2);
-
+                       wil_netif_rx_any(skb, ndev);
                } else {
+                       struct ethhdr *eth = (void *)skb->data;
+
                        skb->protocol = eth_type_trans(skb, ndev);
+
+                       if (is_unicast_ether_addr(eth->h_dest))
+                               wil_rx_reorder(wil, skb);
+                       else
+                               wil_netif_rx_any(skb, ndev);
                }
 
-               wil_netif_rx_any(skb, ndev);
        }
        wil_rx_refill(wil, v->size);
 }
@@ -598,6 +616,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
        if (rc)
                goto out;
 
+       wil->vring2cid_tid[id][0] = cid;
+       wil->vring2cid_tid[id][1] = tid;
+
        cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
 
        rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
@@ -634,12 +655,83 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
 static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
                                       struct sk_buff *skb)
 {
-       struct vring *v = &wil->vring_tx[0];
+       int i;
+       struct ethhdr *eth = (void *)skb->data;
+       int cid = wil_find_cid(wil, eth->h_dest);
+
+       if (cid < 0)
+               return NULL;
+
+       /* TODO: fix for multiple TID */
+       for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
+               if (wil->vring2cid_tid[i][0] == cid) {
+                       struct vring *v = &wil->vring_tx[i];
+                       wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
+                                    __func__, eth->h_dest, i);
+                       if (v->va) {
+                               return v;
+                       } else {
+                               wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
+                               return NULL;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+static void wil_set_da_for_vring(struct wil6210_priv *wil,
+                                struct sk_buff *skb, int vring_index)
+{
+       struct ethhdr *eth = (void *)skb->data;
+       int cid = wil->vring2cid_tid[vring_index][0];
+       memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
+}
+
+static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
+                       struct sk_buff *skb);
+/*
+ * Find 1-st vring and return it; set dest address for this vring in skb
+ * duplicate skb and send it to other active vrings
+ */
+static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
+                                      struct sk_buff *skb)
+{
+       struct vring *v, *v2;
+       struct sk_buff *skb2;
+       int i;
+
+       /* find 1-st vring */
+       for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+               v = &wil->vring_tx[i];
+               if (v->va)
+                       goto found;
+       }
 
-       if (v->va)
-               return v;
+       wil_err(wil, "Tx while no vrings active?\n");
 
        return NULL;
+
+found:
+       wil_dbg_txrx(wil, "BCAST -> ring %d\n", i);
+       wil_set_da_for_vring(wil, skb, i);
+
+       /* find other active vrings and duplicate skb for each */
+       for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
+               v2 = &wil->vring_tx[i];
+               if (!v2->va)
+                       continue;
+               skb2 = skb_copy(skb, GFP_ATOMIC);
+               if (skb2) {
+                       wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
+                       wil_set_da_for_vring(wil, skb2, i);
+                       wil_tx_vring(wil, v2, skb2);
+               } else {
+                       wil_err(wil, "skb_copy failed\n");
+               }
+       }
+
+       return v;
 }
 
 static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
@@ -740,9 +832,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
        }
        _d = &(vring->va[i].tx);
 
-       /* FIXME FW can accept only unicast frames for the peer */
-       memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
-
        pa = dma_map_single(dev, skb->data,
                        skb_headlen(skb), DMA_TO_DEVICE);
 
@@ -836,6 +925,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
 netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        struct wil6210_priv *wil = ndev_to_wil(ndev);
+       struct ethhdr *eth = (void *)skb->data;
        struct vring *vring;
        int rc;
 
@@ -854,9 +944,13 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
 
        /* find vring */
-       vring = wil_find_tx_vring(wil, skb);
+       if (is_unicast_ether_addr(eth->h_dest)) {
+               vring = wil_find_tx_vring(wil, skb);
+       } else {
+               vring = wil_tx_bcast(wil, skb);
+       }
        if (!vring) {
-               wil_err(wil, "No Tx VRING available\n");
+               wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest);
                goto drop;
        }
        /* set up vring entry */
@@ -892,6 +986,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
        struct device *dev = wil_to_dev(wil);
        struct vring *vring = &wil->vring_tx[ringid];
        int done = 0;
+       int cid = wil->vring2cid_tid[ringid][0];
+       struct wil_net_stats *stats = &wil->sta[cid].stats;
 
        if (!vring->va) {
                wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);
@@ -933,9 +1029,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
                if (skb) {
                        if (d->dma.error == 0) {
                                ndev->stats.tx_packets++;
+                               stats->tx_packets++;
                                ndev->stats.tx_bytes += skb->len;
+                               stats->tx_bytes += skb->len;
                        } else {
                                ndev->stats.tx_errors++;
+                               stats->tx_errors++;
                        }
 
                        dev_kfree_skb_any(skb);
index b3828279204c97d4057c7fc8253b5c54d43deed5..bc5706a4f007b11eadd4b53faece30b45e49266f 100644 (file)
@@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
        return (void *)skb->cb;
 }
 
+void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
+void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
+struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
+                                               int size, u16 ssn);
+void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
+                          struct wil_tid_ampdu_rx *r);
+
 #endif /* WIL6210_TXRX_H */
index 1f91eaf95bbebd0dfd70d316943558c5882ed54d..980dccc82b32c3dffc2b2d4a7bdc4c8847fa19a2 100644 (file)
@@ -215,6 +215,46 @@ enum { /* for wil6210_priv.status */
 
 struct pci_dev;
 
+/**
+ * struct tid_ampdu_rx - TID aggregation information (Rx).
+ *
+ * @reorder_buf: buffer to reorder incoming aggregated MPDUs
+ * @reorder_time: jiffies when skb was added
+ * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
+ * @reorder_timer: releases expired frames from the reorder buffer.
+ * @last_rx: jiffies of last rx activity
+ * @head_seq_num: head sequence number in reordering buffer.
+ * @stored_mpdu_num: number of MPDUs in reordering buffer
+ * @ssn: Starting Sequence Number expected to be aggregated.
+ * @buf_size: buffer size for incoming A-MPDUs
+ * @timeout: reset timer value (in TUs).
+ * @dialog_token: dialog token for aggregation session
+ * @rcu_head: RCU head used for freeing this struct
+ * @reorder_lock: serializes access to reorder buffer, see below.
+ *
+ * This structure's lifetime is managed by RCU, assignments to
+ * the array holding it must hold the aggregation mutex.
+ *
+ * The @reorder_lock is used to protect the members of this
+ * struct, except for @timeout, @buf_size and @dialog_token,
+ * which are constant across the lifetime of the struct (the
+ * dialog token being used only for debugging).
+ */
+struct wil_tid_ampdu_rx {
+       spinlock_t reorder_lock; /* see above */
+       struct sk_buff **reorder_buf;
+       unsigned long *reorder_time;
+       struct timer_list session_timer;
+       struct timer_list reorder_timer;
+       unsigned long last_rx;
+       u16 head_seq_num;
+       u16 stored_mpdu_num;
+       u16 ssn;
+       u16 buf_size;
+       u16 timeout;
+       u8 dialog_token;
+};
+
 struct wil6210_stats {
        u64 tsf;
        u32 snr;
@@ -226,6 +266,42 @@ struct wil6210_stats {
        u16 peer_tx_sector;
 };
 
+enum wil_sta_status {
+       wil_sta_unused = 0,
+       wil_sta_conn_pending = 1,
+       wil_sta_connected = 2,
+};
+
+#define WIL_STA_TID_NUM (16)
+
+struct wil_net_stats {
+       unsigned long   rx_packets;
+       unsigned long   tx_packets;
+       unsigned long   rx_bytes;
+       unsigned long   tx_bytes;
+       unsigned long   tx_errors;
+       unsigned long   rx_dropped;
+       u16 last_mcs_rx;
+};
+
+/**
+ * struct wil_sta_info - data for peer
+ *
+ * Peer identified by its CID (connection ID)
+ * NIC performs beam forming for each peer;
+ * if no beam forming done, frame exchange is not
+ * possible.
+ */
+struct wil_sta_info {
+       u8 addr[ETH_ALEN];
+       enum wil_sta_status status;
+       struct wil_net_stats stats;
+       /* Rx BACK */
+       struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
+       unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
+       unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
+};
+
 struct wil6210_priv {
        struct pci_dev *pdev;
        int n_msi;
@@ -267,7 +343,8 @@ struct wil6210_priv {
        /* DMA related */
        struct vring vring_rx;
        struct vring vring_tx[WIL6210_MAX_TX_RINGS];
-       u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN];
+       u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
+       struct wil_sta_info sta[WIL6210_MAX_CID];
        /* scan */
        struct cfg80211_scan_request *scan_request;
 
@@ -334,6 +411,7 @@ void wil_link_off(struct wil6210_priv *wil);
 int wil_up(struct wil6210_priv *wil);
 int wil_down(struct wil6210_priv *wil);
 void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
+int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
 
 void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
 void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
@@ -357,7 +435,9 @@ int wmi_echo(struct wil6210_priv *wil);
 int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
 int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
 int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
+int wmi_rxon(struct wil6210_priv *wil, bool on);
 int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
+int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
 
 int wil6210_init_irq(struct wil6210_priv *wil, int irq);
 void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
index 063963ee422a497ff3ec7dd1dce815f8411690b7..24eed096358104e7c4f4f346bb0efc1bf3066953 100644 (file)
@@ -307,14 +307,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
        u32 freq = ieee80211_channel_to_frequency(ch_no,
                        IEEE80211_BAND_60GHZ);
        struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq);
-       /* TODO convert LE to CPU */
-       s32 signal = 0; /* TODO */
+       s32 signal = data->info.sqi;
        __le16 fc = rx_mgmt_frame->frame_control;
        u32 d_len = le32_to_cpu(data->info.len);
        u16 d_status = le16_to_cpu(data->info.status);
 
-       wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n",
-                   data->info.channel, data->info.mcs, data->info.snr);
+       wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n",
+                   data->info.channel, data->info.mcs, data->info.snr,
+                   data->info.sqi);
        wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
                    le16_to_cpu(fc));
        wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
@@ -384,6 +384,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
                        evt->assoc_req_len, evt->assoc_resp_len);
                return;
        }
+       if (evt->cid >= WIL6210_MAX_CID) {
+               wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
+               return;
+       }
+
        ch = evt->channel + 1;
        wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
                    evt->bssid, ch, evt->cid);
@@ -439,7 +444,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
 
        /* FIXME FW can transmit only ucast frames to peer */
        /* FIXME real ring_id instead of hard coded 0 */
-       memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
+       memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN);
+       wil->sta[evt->cid].status = wil_sta_conn_pending;
 
        wil->pending_connect_cid = evt->cid;
        queue_work(wil->wmi_wq_conn, &wil->connect_worker);
@@ -476,11 +482,11 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
        wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
        wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
        wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
-                   "BF status 0x%08x SNR 0x%08x\n"
+                   "BF status 0x%08x SNR 0x%08x SQI %d%%\n"
                    "Tx Tpt %d goodput %d Rx goodput %d\n"
                    "Sectors(rx:tx) my %d:%d peer %d:%d\n",
                    wil->stats.bf_mcs, wil->stats.tsf, evt->status,
-                   wil->stats.snr, le32_to_cpu(evt->tx_tpt),
+                   wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt),
                    le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
                    wil->stats.my_rx_sector, wil->stats.my_tx_sector,
                    wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
@@ -499,10 +505,16 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
        int sz = eapol_len + ETH_HLEN;
        struct sk_buff *skb;
        struct ethhdr *eth;
+       int cid;
+       struct wil_net_stats *stats = NULL;
 
        wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
                    evt->src_mac);
 
+       cid = wil_find_cid(wil, evt->src_mac);
+       if (cid >= 0)
+               stats = &wil->sta[cid].stats;
+
        if (eapol_len > 196) { /* TODO: revisit size limit */
                wil_err(wil, "EAPOL too large\n");
                return;
@@ -513,6 +525,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
                wil_err(wil, "Failed to allocate skb\n");
                return;
        }
+
        eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);
        memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);
        memcpy(eth->h_source, evt->src_mac, ETH_ALEN);
@@ -521,9 +534,15 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
        skb->protocol = eth_type_trans(skb, ndev);
        if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
                ndev->stats.rx_packets++;
-               ndev->stats.rx_bytes += skb->len;
+               ndev->stats.rx_bytes += sz;
+               if (stats) {
+                       stats->rx_packets++;
+                       stats->rx_bytes += sz;
+               }
        } else {
                ndev->stats.rx_dropped++;
+               if (stats)
+                       stats->rx_dropped++;
        }
 }
 
@@ -552,10 +571,42 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
                              int len)
 {
        struct wmi_vring_ba_status_event *evt = d;
+       struct wil_sta_info *sta;
+       uint i, cid;
+
+       /* TODO: use Rx BA status, not Tx one */
 
        wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
-                   evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize,
-                   __le16_to_cpu(evt->ba_timeout));
+                   evt->ringid,
+                   evt->status == WMI_BA_AGREED ? "OK" : "N/A",
+                   evt->agg_wsize, __le16_to_cpu(evt->ba_timeout));
+
+       if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
+               wil_err(wil, "invalid ring id %d\n", evt->ringid);
+               return;
+       }
+
+       cid = wil->vring2cid_tid[evt->ringid][0];
+       if (cid >= WIL6210_MAX_CID) {
+               wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
+               return;
+       }
+
+       sta = &wil->sta[cid];
+       if (sta->status == wil_sta_unused) {
+               wil_err(wil, "CID %d unused\n", cid);
+               return;
+       }
+
+       wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
+       for (i = 0; i < WIL_STA_TID_NUM; i++) {
+               struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+               sta->tid_rx[i] = NULL;
+               wil_tid_ampdu_rx_free(wil, r);
+               if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
+                       sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
+                                               evt->agg_wsize, 0);
+       }
 }
 
 static const struct {
@@ -893,6 +944,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
        return rc;
 }
 
+/**
+ * wmi_rxon - turn radio on/off
+ * @on:                turn on if true, off otherwise
+ *
+ * Only switch radio. Channel should be set separately.
+ * No timeout for rxon - radio turned on forever unless some other call
+ * turns it off
+ */
+int wmi_rxon(struct wil6210_priv *wil, bool on)
+{
+       int rc;
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_listen_started_event evt;
+       } __packed reply;
+
+       wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off");
+
+       if (on) {
+               rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
+                             WMI_LISTEN_STARTED_EVENTID,
+                             &reply, sizeof(reply), 100);
+               if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
+                       rc = -EINVAL;
+       } else {
+               rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
+                             WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
+       }
+
+       return rc;
+}
+
 int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
 {
        struct wireless_dev *wdev = wil->wdev;
@@ -906,6 +989,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
                },
                .mid = 0, /* TODO - what is it? */
                .decap_trans_type = WMI_DECAP_TYPE_802_3,
+               .reorder_type = WMI_RX_SW_REORDER,
        };
        struct {
                struct wil6210_mbox_hdr_wmi wmi;
@@ -973,6 +1057,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
        return 0;
 }
 
+int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
+{
+       struct wmi_disconnect_sta_cmd cmd = {
+               .disconnect_reason = cpu_to_le16(reason),
+       };
+       memcpy(cmd.dst_mac, mac, ETH_ALEN);
+
+       wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason);
+
+       return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd));
+}
+
 void wmi_event_flush(struct wil6210_priv *wil)
 {
        struct pending_wmi_event *evt, *t;
index bf93ea859f2d7f1fc05257a86a0b5b1525dd62c3..1fe41af81a597a4a90c75aac5557567725b09fc5 100644 (file)
@@ -67,7 +67,7 @@
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/jiffies.h>
-#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
 #include "atmel.h"
 
 #define DRIVER_MAJOR 0
@@ -2273,7 +2273,7 @@ static int atmel_set_freq(struct net_device *dev,
 
                /* Hack to fall through... */
                fwrq->e = 0;
-               fwrq->m = ieee80211_freq_to_dsss_chan(f);
+               fwrq->m = ieee80211_frequency_to_channel(f);
        }
        /* Setting by channel number */
        if ((fwrq->m > 1000) || (fwrq->e > 0))
@@ -2434,8 +2434,8 @@ static int atmel_get_range(struct net_device *dev,
                        range->freq[k].i = i; /* List index */
 
                        /* Values in MHz -> * 10^5 * 10 */
-                       range->freq[k].m = (ieee80211_dsss_chan_to_freq(i) *
-                                           100000);
+                       range->freq[k].m = 100000 *
+                        ieee80211_channel_to_frequency(i, IEEE80211_BAND_2GHZ);
                        range->freq[k++].e = 1;
                }
                range->num_frequency = k;
index 51ff0b198d0a94c6486bec11136a6b08ea9d29c2..088d544ec63f940b2a7b2234f1eac9b7458a19ce 100644 (file)
@@ -92,7 +92,7 @@ config B43_SDIO
 # if we can do DMA.
 config B43_BCMA_PIO
        bool
-       depends on B43_BCMA
+       depends on B43 && B43_BCMA
        select BCMA_BLOCKIO
        default y
 
index 822aad8842f4defbe8b24af07b4f0559f53223b5..50517b801cb42d40137d2c0739440220ce8e2151 100644 (file)
@@ -86,7 +86,7 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev,
 
 static inline bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
 {
-       return 0;
+       return false;
 }
 
 static inline void b43_debugfs_init(void)
index c75237eb55a16b7e17de051ff7f51f1ca62c4fe1..69fc3d65531a7eeb88c4901f804ab197dbbb939e 100644 (file)
@@ -1549,7 +1549,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
 
        bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
-       len = min((size_t) dev->wl->current_beacon->len,
+       len = min_t(size_t, dev->wl->current_beacon->len,
                  0x200 - sizeof(struct b43_plcp_hdr6));
        rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
 
index f01676ac481b25071e9f7aae9ad790dbd5836ff0..dbaa51890198945b7552ed506bc3c8bfe4ba2359 100644 (file)
@@ -133,9 +133,9 @@ void b43_phy_exit(struct b43_wldev *dev)
 bool b43_has_hardware_pctl(struct b43_wldev *dev)
 {
        if (!dev->phy.hardware_power_control)
-               return 0;
+               return false;
        if (!dev->phy.ops->supports_hwpctl)
-               return 0;
+               return false;
        return dev->phy.ops->supports_hwpctl(dev);
 }
 
index a73ff8c9deb55ff320f5e3ba46ac6b0fc8dabef1..a4ff5e2a42b95da1fedc6c64f1ef3ac8042afb5b 100644 (file)
@@ -637,7 +637,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
 
                ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
                if (!(ctl & B43_PIO8_RXCTL_FRAMERDY))
-                       return 0;
+                       return false;
                b43_piorx_write32(q, B43_PIO8_RXCTL,
                                  B43_PIO8_RXCTL_FRAMERDY);
                for (i = 0; i < 10; i++) {
@@ -651,7 +651,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
 
                ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
                if (!(ctl & B43_PIO_RXCTL_FRAMERDY))
-                       return 0;
+                       return false;
                b43_piorx_write16(q, B43_PIO_RXCTL,
                                  B43_PIO_RXCTL_FRAMERDY);
                for (i = 0; i < 10; i++) {
@@ -662,7 +662,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
                }
        }
        b43dbg(q->dev->wl, "PIO RX timed out\n");
-       return 1;
+       return true;
 data_ready:
 
        /* Get the preamble (RX header) */
@@ -759,7 +759,7 @@ data_ready:
 
        b43_rx(q->dev, skb, rxhdr);
 
-       return 1;
+       return true;
 
 rx_error:
        if (err_msg)
@@ -769,7 +769,7 @@ rx_error:
        else
                b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY);
 
-       return 1;
+       return true;
 }
 
 void b43_pio_rx(struct b43_pio_rxqueue *q)
index 8e8431d4eb0c0d9c4ee86463e5823a91cca952dc..3190493bd07f4ce272ba90fbe61aa0a32f9d0535 100644 (file)
@@ -40,7 +40,7 @@ static int get_integer(const char *buf, size_t count)
 
        if (count == 0)
                goto out;
-       count = min(count, (size_t) 10);
+       count = min_t(size_t, count, 10);
        memcpy(tmp, buf, count);
        ret = simple_strtol(tmp, NULL, 10);
       out:
index 218a0f37af46627570ba4e1e1a8e359edb470ddb..31adb8cf0291fb0bbebf1a6896c8f4ff4d7288b9 100644 (file)
@@ -337,7 +337,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                        /* iv16 */
                        memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3);
                } else {
-                       iv_len = min((size_t) info->control.hw_key->iv_len,
+                       iv_len = min_t(size_t, info->control.hw_key->iv_len,
                                     ARRAY_SIZE(txhdr->iv));
                        memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
                }
index 349c77605231a660dbf398b3a93a13978715de3d..1aec2146a2bfb5ecfe3fe6d8452236799058d9c8 100644 (file)
@@ -978,7 +978,7 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
 
        bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
-       len = min((size_t)dev->wl->current_beacon->len,
+       len = min_t(size_t, dev->wl->current_beacon->len,
                  0x200 - sizeof(struct b43legacy_plcp_hdr6));
        rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
 
@@ -1155,7 +1155,7 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
        b43legacy_write_probe_resp_plcp(dev, 0x350, size,
                                        &b43legacy_b_ratetable[3]);
 
-       size = min((size_t)size,
+       size = min_t(size_t, size,
                   0x200 - sizeof(struct b43legacy_plcp_hdr6));
        b43legacy_write_template_common(dev, probe_resp_data,
                                        size, ram_offset,
index 57f8b089767ca0f7d9700e16fee71bbe76998855..2a1da15c913b0704eb5aa04d179e6eef70e0cfa6 100644 (file)
@@ -42,7 +42,7 @@ static int get_integer(const char *buf, size_t count)
 
        if (count == 0)
                goto out;
-       count = min(count, (size_t)10);
+       count = min_t(size_t, count, 10);
        memcpy(tmp, buf, count);
        ret = simple_strtol(tmp, NULL, 10);
 out:
index 86588c9ff0f2b6cddee0b3a7da5455fd05b29a9b..34bf3f0b729f79c901ba5351bd47043591118563 100644 (file)
@@ -254,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                                   B43legacy_TX4_MAC_KEYALG_SHIFT) &
                                   B43legacy_TX4_MAC_KEYALG;
                        wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control);
-                       iv_len = min((size_t)info->control.hw_key->iv_len,
+                       iv_len = min_t(size_t, info->control.hw_key->iv_len,
                                     ARRAY_SIZE(txhdr->iv));
                        memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
                } else {
index 07e7d2520257846f0278891ffe74a368a0b0b851..4a6508e7e3a1058eea38aabc1c95d4d0ad4a40f9 100644 (file)
 /* Maximum milliseconds to wait for F2 to come up */
 #define SDIO_WAIT_F2RDY        3000
 
+#define BRCMF_DEFAULT_TXGLOM_SIZE      32  /* max tx frames in glom chain */
+#define BRCMF_DEFAULT_RXGLOM_SIZE      32  /* max rx frames in glom chain */
+
+static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
+module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
+MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
 
 static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
 {
@@ -487,7 +493,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
        struct mmc_request mmc_req;
        struct mmc_command mmc_cmd;
        struct mmc_data mmc_dat;
-       struct sg_table st;
        struct scatterlist *sgl;
        int ret = 0;
 
@@ -532,16 +537,11 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
        pkt_offset = 0;
        pkt_next = target_list->next;
 
-       if (sg_alloc_table(&st, max_seg_cnt, GFP_KERNEL)) {
-               ret = -ENOMEM;
-               goto exit;
-       }
-
        memset(&mmc_req, 0, sizeof(struct mmc_request));
        memset(&mmc_cmd, 0, sizeof(struct mmc_command));
        memset(&mmc_dat, 0, sizeof(struct mmc_data));
 
-       mmc_dat.sg = st.sgl;
+       mmc_dat.sg = sdiodev->sgtable.sgl;
        mmc_dat.blksz = func_blk_sz;
        mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
        mmc_cmd.opcode = SD_IO_RW_EXTENDED;
@@ -557,7 +557,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
        while (seg_sz) {
                req_sz = 0;
                sg_cnt = 0;
-               sgl = st.sgl;
+               sgl = sdiodev->sgtable.sgl;
                /* prep sg table */
                while (pkt_next != (struct sk_buff *)target_list) {
                        pkt_data = pkt_next->data + pkt_offset;
@@ -639,7 +639,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
        }
 
 exit:
-       sg_free_table(&st);
+       sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents);
        while ((pkt_next = __skb_dequeue(&local_list)) != NULL)
                brcmu_pkt_buf_free_skb(pkt_next);
 
@@ -863,6 +863,29 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
        return 0;
 }
 
+static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
+{
+       uint nents;
+       int err;
+
+       if (!sdiodev->sg_support)
+               return;
+
+       nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz);
+       nents += (nents >> 4) + 1;
+
+       WARN_ON(nents > sdiodev->max_segment_count);
+
+       brcmf_dbg(TRACE, "nents=%d\n", nents);
+       err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL);
+       if (err < 0) {
+               brcmf_err("allocation failed: disable scatter-gather");
+               sdiodev->sg_support = false;
+       }
+
+       sdiodev->txglomsz = brcmf_sdiod_txglomsz;
+}
+
 static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
 {
        if (sdiodev->bus) {
@@ -880,6 +903,7 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
        sdio_disable_func(sdiodev->func[1]);
        sdio_release_host(sdiodev->func[1]);
 
+       sg_free_table(&sdiodev->sgtable);
        sdiodev->sbwad = 0;
 
        return 0;
@@ -935,6 +959,11 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
                                           SG_MAX_SINGLE_ALLOC);
        sdiodev->max_segment_size = host->max_seg_size;
 
+       /* allocate scatter-gather table. sg support
+        * will be disabled upon allocation failure.
+        */
+       brcmf_sdiod_sgtable_alloc(sdiodev);
+
        /* try to attach to the target device */
        sdiodev->bus = brcmf_sdio_probe(sdiodev);
        if (!sdiodev->bus) {
@@ -1072,9 +1101,7 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        int ret = 0;
 
-       brcmf_dbg(SDIO, "\n");
-
-       atomic_set(&sdiodev->suspend, true);
+       brcmf_dbg(SDIO, "Enter\n");
 
        sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
        if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
@@ -1082,9 +1109,12 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
                return -EINVAL;
        }
 
+       atomic_set(&sdiodev->suspend, true);
+
        ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
        if (ret) {
                brcmf_err("Failed to set pm_flags\n");
+               atomic_set(&sdiodev->suspend, false);
                return ret;
        }
 
@@ -1098,6 +1128,7 @@ static int brcmf_ops_sdio_resume(struct device *dev)
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 
+       brcmf_dbg(SDIO, "Enter\n");
        brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
        atomic_set(&sdiodev->suspend, false);
        return 0;
index d4d966beb840b832ecc079a9317d6a3b8baa22d8..7d28cd3850925a7af0a4b9f34c2888afa83e0d03 100644 (file)
@@ -1040,12 +1040,12 @@ void brcmf_detach(struct device *dev)
 
        brcmf_cfg80211_detach(drvr->config);
 
+       brcmf_fws_deinit(drvr);
+
        brcmf_bus_detach(drvr);
 
        brcmf_proto_detach(drvr);
 
-       brcmf_fws_deinit(drvr);
-
        brcmf_debugfs_detach(drvr);
        bus_if->drvr = NULL;
        kfree(drvr);
index 631d5dc5b6d52c8dc13c7602e976d8fb9f85a475..a111b6fbbeba337e1bacc041504d5362d0f6e854 100644 (file)
@@ -113,8 +113,6 @@ struct rte_console {
 #define BRCMF_TXBOUND  20      /* Default for max tx frames in
                                 one scheduling */
 
-#define BRCMF_DEFAULT_TXGLOM_SIZE      32  /* max tx frames in glom chain */
-
 #define BRCMF_TXMINMAX 1       /* Max tx frames if rx still pending */
 
 #define MEMBLOCK       2048    /* Block size used for downloading
@@ -304,7 +302,6 @@ struct rte_console {
 /* Flags for SDH calls */
 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 
-#define BRCMF_IDLE_IMMEDIATE   (-1)    /* Enter idle immediately */
 #define BRCMF_IDLE_ACTIVE      0       /* Do not request any SD clock change
                                         * when idle
                                         */
@@ -485,7 +482,6 @@ struct brcmf_sdio {
 
        u8 tx_hdrlen;           /* sdio bus header length for tx packet */
        bool txglom;            /* host tx glomming enable flag */
-       struct sk_buff *txglom_sgpad;   /* scatter-gather padding buffer */
        u16 head_align;         /* buffer pointer alignment */
        u16 sgentry_align;      /* scatter-gather buffer alignment */
 };
@@ -512,10 +508,6 @@ static const uint max_roundup = 512;
 
 #define ALIGNMENT  4
 
-static int brcmf_sdio_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
-module_param_named(txglomsz, brcmf_sdio_txglomsz, int, 0);
-MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
-
 enum brcmf_sdio_frmtype {
        BRCMF_SDIO_FT_NORMAL,
        BRCMF_SDIO_FT_SUPER,
@@ -771,8 +763,6 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
        return err;
 }
 
-#define PKT_AVAILABLE()                (intstatus & I_HMB_FRAME_IND)
-
 #define HOSTINTMASK            (I_HMB_SW_MASK | I_CHIPACTIVE)
 
 /* Turn backplane clock on or off */
@@ -871,7 +861,6 @@ static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
                }
 #endif                         /* defined (DEBUG) */
 
-               bus->activity = true;
        } else {
                clkreq = 0;
 
@@ -1241,6 +1230,28 @@ static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
        bus->cur_read.len = 0;
 }
 
+static void brcmf_sdio_txfail(struct brcmf_sdio *bus)
+{
+       struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
+       u8 i, hi, lo;
+
+       /* On failure, abort the command and terminate the frame */
+       brcmf_err("sdio error, abort command and terminate frame\n");
+       bus->sdcnt.tx_sderrs++;
+
+       brcmf_sdiod_abort(sdiodev, SDIO_FUNC_2);
+       brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL);
+       bus->sdcnt.f1regdata++;
+
+       for (i = 0; i < 3; i++) {
+               hi = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL);
+               lo = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL);
+               bus->sdcnt.f1regdata += 2;
+               if ((hi == 0) && (lo == 0))
+                       break;
+       }
+}
+
 /* return total length of buffer chain */
 static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)
 {
@@ -2101,9 +2112,8 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
        if (lastfrm && chain_pad)
                tail_pad += blksize - chain_pad;
        if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
-               pkt_pad = bus->txglom_sgpad;
-               if (pkt_pad == NULL)
-                         brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
+               pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop +
+                                               bus->head_align);
                if (pkt_pad == NULL)
                        return -ENOMEM;
                ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
@@ -2112,8 +2122,9 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
                memcpy(pkt_pad->data,
                       pkt->data + pkt->len - tail_chop,
                       tail_chop);
-               *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
+               *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
                skb_trim(pkt, pkt->len - tail_chop);
+               skb_trim(pkt_pad, tail_pad + tail_chop);
                __skb_queue_after(pktq, pkt, pkt_pad);
        } else {
                ntail = pkt->data_len + tail_pad -
@@ -2159,7 +2170,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                 * already properly aligned and does not
                 * need an sdpcm header.
                 */
-               if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
+               if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
                        continue;
 
                /* align packet data pointer */
@@ -2168,7 +2179,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                        return ret;
                head_pad = (u16)ret;
                if (head_pad)
-                       memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen);
+                       memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad);
 
                total_len += pkt_next->len;
 
@@ -2193,10 +2204,10 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                if (BRCMF_BYTES_ON() &&
                    ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
                     (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
-                       brcmf_dbg_hex_dump(true, pkt_next, hd_info.len,
+                       brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len,
                                           "Tx Frame:\n");
                else if (BRCMF_HDRS_ON())
-                       brcmf_dbg_hex_dump(true, pkt_next,
+                       brcmf_dbg_hex_dump(true, pkt_next->data,
                                           head_pad + bus->tx_hdrlen,
                                           "Tx Header:\n");
        }
@@ -2223,11 +2234,11 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
        u8 *hdr;
        u32 dat_offset;
        u16 tail_pad;
-       u32 dummy_flags, chop_len;
+       u16 dummy_flags, chop_len;
        struct sk_buff *pkt_next, *tmp, *pkt_prev;
 
        skb_queue_walk_safe(pktq, pkt_next, tmp) {
-               dummy_flags = *(u32 *)(pkt_next->cb);
+               dummy_flags = *(u16 *)(pkt_next->cb);
                if (dummy_flags & ALIGN_SKB_FLAG) {
                        chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
                        if (chop_len) {
@@ -2256,7 +2267,6 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                            uint chan)
 {
        int ret;
-       int i;
        struct sk_buff *pkt_next, *tmp;
 
        brcmf_dbg(TRACE, "Enter\n");
@@ -2269,28 +2279,9 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
        ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
        bus->sdcnt.f2txdata++;
 
-       if (ret < 0) {
-               /* On failure, abort the command and terminate the frame */
-               brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
-                         ret);
-               bus->sdcnt.tx_sderrs++;
+       if (ret < 0)
+               brcmf_sdio_txfail(bus);
 
-               brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
-               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
-                                 SFC_WF_TERM, NULL);
-               bus->sdcnt.f1regdata++;
-
-               for (i = 0; i < 3; i++) {
-                       u8 hi, lo;
-                       hi = brcmf_sdiod_regrb(bus->sdiodev,
-                                              SBSDIO_FUNC1_WFRAMEBCHI, NULL);
-                       lo = brcmf_sdiod_regrb(bus->sdiodev,
-                                              SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-                       bus->sdcnt.f1regdata += 2;
-                       if ((hi == 0) && (lo == 0))
-                               break;
-               }
-       }
        sdio_release_host(bus->sdiodev->func[1]);
 
 done:
@@ -2323,7 +2314,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
                __skb_queue_head_init(&pktq);
                if (bus->txglom)
                        pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
-                                       brcmf_sdio_txglomsz);
+                                       bus->sdiodev->txglomsz);
                pkt_num = min_t(u32, pkt_num,
                                brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol));
                spin_lock_bh(&bus->txqlock);
@@ -2342,7 +2333,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
                cnt += i;
 
                /* In poll mode, need to check for other events */
-               if (!bus->intr && cnt) {
+               if (!bus->intr) {
                        /* Check device status, signal pending interrupt */
                        sdio_claim_host(bus->sdiodev->func[1]);
                        ret = r_sdreg32(bus, &intstatus,
@@ -2448,12 +2439,21 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
        }
 }
 
+static void atomic_orr(int val, atomic_t *v)
+{
+       int old_val;
+
+       old_val = atomic_read(v);
+       while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
+               old_val = atomic_read(v);
+}
+
 static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
 {
        struct brcmf_core *buscore;
        u32 addr;
        unsigned long val;
-       int n, ret;
+       int ret;
 
        buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
        addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
@@ -2461,7 +2461,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
        val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
        bus->sdcnt.f1regdata++;
        if (ret != 0)
-               val = 0;
+               return ret;
 
        val &= bus->hostintmask;
        atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
@@ -2470,13 +2470,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
        if (val) {
                brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
                bus->sdcnt.f1regdata++;
-       }
-
-       if (ret) {
-               atomic_set(&bus->intstatus, 0);
-       } else if (val) {
-               for_each_set_bit(n, &val, 32)
-                       set_bit(n, (unsigned long *)&bus->intstatus.counter);
+               atomic_orr(val, &bus->intstatus);
        }
 
        return ret;
@@ -2486,10 +2480,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 {
        u32 newstatus = 0;
        unsigned long intstatus;
-       uint rxlimit = bus->rxbound;    /* Rx frames to read before resched */
        uint txlimit = bus->txbound;    /* Tx frames to send before resched */
-       uint framecnt = 0;      /* Temporary counter of tx/rx frames */
-       int err = 0, n;
+       uint framecnt;                  /* Temporary counter of tx/rx frames */
+       int err = 0;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -2586,58 +2579,30 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
                intstatus &= ~I_HMB_FRAME_IND;
 
        /* On frame indication, read available frames */
-       if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) {
-               framecnt = brcmf_sdio_readframes(bus, rxlimit);
+       if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) {
+               brcmf_sdio_readframes(bus, bus->rxbound);
                if (!bus->rxpending)
                        intstatus &= ~I_HMB_FRAME_IND;
-               rxlimit -= min(framecnt, rxlimit);
        }
 
        /* Keep still-pending events for next scheduling */
-       if (intstatus) {
-               for_each_set_bit(n, &intstatus, 32)
-                       set_bit(n, (unsigned long *)&bus->intstatus.counter);
-       }
+       if (intstatus)
+               atomic_orr(intstatus, &bus->intstatus);
 
        brcmf_sdio_clrintr(bus);
 
        if (data_ok(bus) && bus->ctrl_frame_stat &&
-               (bus->clkstate == CLK_AVAIL)) {
-               int i;
+           (bus->clkstate == CLK_AVAIL)) {
 
                sdio_claim_host(bus->sdiodev->func[1]);
                err = brcmf_sdiod_send_buf(bus->sdiodev, bus->ctrl_frame_buf,
                                           (u32)bus->ctrl_frame_len);
 
-               if (err < 0) {
-                       /* On failure, abort the command and
-                               terminate the frame */
-                       brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
-                                 err);
-                       bus->sdcnt.tx_sderrs++;
-
-                       brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
-
-                       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
-                                         SFC_WF_TERM, &err);
-                       bus->sdcnt.f1regdata++;
-
-                       for (i = 0; i < 3; i++) {
-                               u8 hi, lo;
-                               hi = brcmf_sdiod_regrb(bus->sdiodev,
-                                                      SBSDIO_FUNC1_WFRAMEBCHI,
-                                                      &err);
-                               lo = brcmf_sdiod_regrb(bus->sdiodev,
-                                                      SBSDIO_FUNC1_WFRAMEBCLO,
-                                                      &err);
-                               bus->sdcnt.f1regdata += 2;
-                               if ((hi == 0) && (lo == 0))
-                                       break;
-                       }
-
-               } else {
+               if (err < 0)
+                       brcmf_sdio_txfail(bus);
+               else
                        bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
-               }
+
                sdio_release_host(bus->sdiodev->func[1]);
                bus->ctrl_frame_stat = false;
                brcmf_sdio_wait_event_wakeup(bus);
@@ -2648,8 +2613,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
                 && data_ok(bus)) {
                framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :
                                            txlimit;
-               framecnt = brcmf_sdio_sendfromq(bus, framecnt);
-               txlimit -= framecnt;
+               brcmf_sdio_sendfromq(bus, framecnt);
        }
 
        if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
@@ -2659,19 +2623,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
                   atomic_read(&bus->ipend) > 0 ||
                   (!atomic_read(&bus->fcstate) &&
                    brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
-                   data_ok(bus)) || PKT_AVAILABLE()) {
+                   data_ok(bus))) {
                atomic_inc(&bus->dpc_tskcnt);
        }
-
-       /* If we're done for now, turn off clock request. */
-       if ((bus->clkstate != CLK_PENDING)
-           && bus->idletime == BRCMF_IDLE_IMMEDIATE) {
-               bus->activity = false;
-               brcmf_dbg(SDIO, "idle state\n");
-               sdio_claim_host(bus->sdiodev->func[1]);
-               brcmf_sdio_bus_sleep(bus, true, false);
-               sdio_release_host(bus->sdiodev->func[1]);
-       }
 }
 
 static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
@@ -2686,15 +2640,13 @@ static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
 static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
 {
        int ret = -EBADE;
-       uint datalen, prec;
+       uint prec;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        struct brcmf_sdio *bus = sdiodev->bus;
        ulong flags;
 
-       brcmf_dbg(TRACE, "Enter\n");
-
-       datalen = pkt->len;
+       brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
 
        /* Add space for the header */
        skb_push(pkt, bus->tx_hdrlen);
@@ -2709,6 +2661,8 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
 
        /* Priority based enq */
        spin_lock_irqsave(&bus->txqlock, flags);
+       /* reset bus_flags in packet cb */
+       *(u16 *)(pkt->cb) = 0;
        if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
                skb_pull(pkt, bus->tx_hdrlen);
                brcmf_err("out of bus->txq !!!\n");
@@ -2818,38 +2772,15 @@ break2:
 
 static int brcmf_sdio_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 {
-       int i;
        int ret;
 
        bus->ctrl_frame_stat = false;
        ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len);
 
-       if (ret < 0) {
-               /* On failure, abort the command and terminate the frame */
-               brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
-                         ret);
-               bus->sdcnt.tx_sderrs++;
-
-               brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
-
-               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
-                                 SFC_WF_TERM, NULL);
-               bus->sdcnt.f1regdata++;
-
-               for (i = 0; i < 3; i++) {
-                       u8 hi, lo;
-                       hi = brcmf_sdiod_regrb(bus->sdiodev,
-                                              SBSDIO_FUNC1_WFRAMEBCHI, NULL);
-                       lo = brcmf_sdiod_regrb(bus->sdiodev,
-                                              SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-                       bus->sdcnt.f1regdata += 2;
-                       if (hi == 0 && lo == 0)
-                               break;
-               }
-               return ret;
-       }
-
-       bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
+       if (ret < 0)
+               brcmf_sdio_txfail(bus);
+       else
+               bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
 
        return ret;
 }
@@ -2948,15 +2879,6 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
                } while (ret < 0 && retries++ < TXRETRIES);
        }
 
-       if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) &&
-           atomic_read(&bus->dpc_tskcnt) == 0) {
-               bus->activity = false;
-               sdio_claim_host(bus->sdiodev->func[1]);
-               brcmf_dbg(INFO, "idle\n");
-               brcmf_sdio_clkctl(bus, CLK_NONE, true);
-               sdio_release_host(bus->sdiodev->func[1]);
-       }
-
        if (ret)
                bus->sdcnt.tx_ctlerrs++;
        else
@@ -3527,10 +3449,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
                bus->txglom = false;
                value = 1;
                pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
-               bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size);
-               if (!bus->txglom_sgpad)
-                       brcmf_err("allocating txglom padding skb failed, reduced performance\n");
-
                err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
                                           &value, sizeof(u32));
                if (err < 0) {
@@ -3758,8 +3676,8 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
                                              datawork);
 
        while (atomic_read(&bus->dpc_tskcnt)) {
+               atomic_set(&bus->dpc_tskcnt, 0);
                brcmf_sdio_dpc(bus);
-               atomic_dec(&bus->dpc_tskcnt);
        }
 }
 
@@ -4253,7 +4171,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
                        brcmf_chip_detach(bus->ci);
                }
 
-               brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
                kfree(bus->rxbuf);
                kfree(bus->hdrbuf);
                kfree(bus);
index 5e53eb1b2ffaf6a818afad9d15a27507e211f288..3deab7959a0d9a5c3b22ad757caf4615b283b596 100644 (file)
@@ -180,6 +180,8 @@ struct brcmf_sdio_dev {
        uint max_request_size;
        ushort max_segment_count;
        uint max_segment_size;
+       uint txglomsz;
+       struct sg_table sgtable;
 };
 
 /* sdio core registers */
index a54db918574773f517b5acf100230971935ff0e5..00bd1e16c3ce7155e0f575e2682a29714b8df50b 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/kernel.h>
 #include <linux/etherdevice.h>
+#include <linux/module.h>
 #include <net/cfg80211.h>
 #include <net/netlink.h>
 
@@ -251,6 +252,10 @@ struct parsed_vndr_ies {
        struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
 };
 
+static int brcmf_roamoff;
+module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
+MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
+
 /* Quarter dBm units to mW
  * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
  * Table is offset so the last entry is largest mW value that fits in
@@ -4444,7 +4449,9 @@ static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
        u32 event = e->event_code;
        u16 flags = e->flags;
 
-       if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
+       if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
+           (event == BRCMF_E_DISASSOC_IND) ||
+           ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
                brcmf_dbg(CONN, "Processing link down\n");
                return true;
        }
@@ -4688,6 +4695,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
        struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        struct ieee80211_channel *chan;
        s32 err = 0;
+       u16 reason;
 
        if (ifp->vif->mode == WL_MODE_AP) {
                err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
@@ -4709,9 +4717,15 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
                if (!brcmf_is_ibssmode(ifp->vif)) {
                        brcmf_bss_connect_done(cfg, ndev, e, false);
                        if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
-                                              &ifp->vif->sme_state))
-                               cfg80211_disconnected(ndev, 0, NULL, 0,
+                                              &ifp->vif->sme_state)) {
+                               reason = 0;
+                               if (((e->event_code == BRCMF_E_DEAUTH_IND) ||
+                                    (e->event_code == BRCMF_E_DISASSOC_IND)) &&
+                                   (e->reason != WLAN_REASON_UNSPECIFIED))
+                                       reason = e->reason;
+                               cfg80211_disconnected(ndev, reason, NULL, 0,
                                                      GFP_KERNEL);
+                       }
                }
                brcmf_link_down(ifp->vif);
                brcmf_init_prof(ndev_to_prof(ndev));
@@ -4905,11 +4919,8 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
 
        cfg->scan_request = NULL;
        cfg->pwr_save = true;
-       cfg->roam_on = true;    /* roam on & off switch.
-                                we enable roam per default */
-       cfg->active_scan = true;        /* we do active scan for
-                                specific scan per default */
-       cfg->dongle_up = false; /* dongle is not up yet */
+       cfg->active_scan = true;        /* we do active scan per default */
+       cfg->dongle_up = false;         /* dongle is not up yet */
        err = brcmf_init_priv_mem(cfg);
        if (err)
                return err;
@@ -5029,7 +5040,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
 }
 
 static s32
-brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
+brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
 {
        s32 err = 0;
        __le32 roamtrigger[2];
@@ -5039,7 +5050,7 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
         * Setup timeout if Beacons are lost and roam is
         * off to report link down
         */
-       if (roamvar) {
+       if (brcmf_roamoff) {
                err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
                if (err) {
                        brcmf_err("bcn_timeout error (%d)\n", err);
@@ -5051,8 +5062,9 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
         * Enable/Disable built-in roaming to allow supplicant
         * to take care of roaming
         */
-       brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
-       err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
+       brcmf_dbg(INFO, "Internal Roaming = %s\n",
+                 brcmf_roamoff ? "Off" : "On");
+       err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
        if (err) {
                brcmf_err("roam_off error (%d)\n", err);
                goto dongle_rom_out;
@@ -5294,6 +5306,8 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        u32 band_list[3];
        u32 nmode;
        u32 bw_cap[2] = { 0, 0 };
+       u32 rxchain;
+       u32 nchain;
        s8 phy;
        s32 err;
        u32 nband;
@@ -5330,6 +5344,16 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
                  bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
 
+       err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
+       if (err) {
+               brcmf_err("rxchain error (%d)\n", err);
+               nchain = 1;
+       } else {
+               for (nchain = 0; rxchain; nchain++)
+                       rxchain = rxchain & (rxchain - 1);
+       }
+       brcmf_dbg(INFO, "nchain=%d\n", nchain);
+
        err = brcmf_construct_reginfo(cfg, bw_cap);
        if (err) {
                brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
@@ -5358,10 +5382,7 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
                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;
+               memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
                band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
                bands[band->band] = band;
        }
@@ -5408,7 +5429,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
        brcmf_dbg(INFO, "power save set to %s\n",
                  (power_mode ? "enabled" : "disabled"));
 
-       err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
+       err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
        if (err)
                goto default_conf_out;
        err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
index 254feed2860e968d6dd52860c7cc66d23e5d0baf..5715bb0708cf39c738b0e915c3c12cadd298fe4a 100644 (file)
@@ -402,7 +402,6 @@ struct brcmf_cfg80211_info {
        bool ibss_starter;
        bool pwr_save;
        bool dongle_up;
-       bool roam_on;
        bool scan_tried;
        u8 *dcmd_buf;
        u8 *extra_buf;
index 5a9ffd3a6a6caa0d1c98a27cc238de4e8e5047cb..e23d67e0bfe66806f1498e81fbcb82c4b3675a40 100644 (file)
@@ -202,8 +202,8 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
                }
 
                /* calculate the block size */
-               tx_size = block_size = min((size_t)(firmware->size - put),
-                       (size_t)DOWNLOAD_BLOCK_SIZE);
+               tx_size = block_size = min_t(size_t, firmware->size - put,
+                                       DOWNLOAD_BLOCK_SIZE);
 
                memcpy(buf, &firmware->data[put], block_size);
                if (block_size < DOWNLOAD_BLOCK_SIZE) {
index d36e252d2ccbc0041a5b0c1669fe396c2c18db73..596525528f50504afe3005d98ac0ab47d3e26453 100644 (file)
@@ -147,7 +147,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
 
        if (!sta->ap && sta->u.sta.challenge)
                kfree(sta->u.sta.challenge);
-       del_timer(&sta->timer);
+       del_timer_sync(&sta->timer);
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 
        kfree(sta);
index 9f825f2620da749ca2d8090c55171eb021bcf77a..b6ec51923b203afb589e49738a13d87a6c37a836 100644 (file)
@@ -677,6 +677,8 @@ static const struct pcmcia_device_id hostap_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID12(
                "ZoomAir 11Mbps High", "Rate wireless Networking",
                0x273fe3db, 0x32a1eaee),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card",
+               0xa37434e9, 0x9762e8f1),
        PCMCIA_DEVICE_PROD_ID123(
                "Pretec", "CompactWLAN Card 802.11b", "2.5",
                0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
index 3aba49259ef1886d09157559977cb7f72ac1d944..dfc6dfc56d52fa8029beb5e25826c61908b02286 100644 (file)
@@ -7065,7 +7065,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev,
        if (wrqu->data.length > IW_ESSID_MAX_SIZE)
                return -E2BIG;
 
-       wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
+       wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
        memset(priv->nick, 0, sizeof(priv->nick));
        memcpy(priv->nick, extra, wrqu->data.length);
 
index 139326065bd923aad89a867774168480f7a83d0c..c5aa404069f3b14d4c9bba36987faeed088cba58 100644 (file)
@@ -9169,7 +9169,7 @@ static int ipw_wx_set_nick(struct net_device *dev,
        if (wrqu->data.length > IW_ESSID_MAX_SIZE)
                return -E2BIG;
        mutex_lock(&priv->mutex);
-       wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
+       wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
        memset(priv->nick, 0, sizeof(priv->nick));
        memcpy(priv->nick, extra, wrqu->data.length);
        IPW_DEBUG_TRACE("<<\n");
index 0487461ae4da22053607bb49178e296787e18dc3..dc1d20cf64ee9b04b83b7d28495b696a44694317 100644 (file)
@@ -1248,14 +1248,7 @@ il3945_rx_handle(struct il_priv *il)
                len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
                len += sizeof(u32);     /* account for status word */
 
-               /* Reclaim a command buffer only if this packet is a response
-                *   to a (driver-originated) command.
-                * If the packet (e.g. Rx frame) originated from uCode,
-                *   there is no command buffer to reclaim.
-                * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
-                *   but apparently a few don't get set; catch them here. */
-               reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
-                   pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX;
+               reclaim = il_need_reclaim(il, pkt);
 
                /* Based on type of command response or notification,
                 *   handle those that need handling via function in
@@ -1495,12 +1488,14 @@ il3945_irq_tasklet(struct il_priv *il)
        if (inta & CSR_INT_BIT_WAKEUP) {
                D_ISR("Wakeup interrupt\n");
                il_rx_queue_update_write_ptr(il, &il->rxq);
+
+               spin_lock_irqsave(&il->lock, flags);
                il_txq_update_write_ptr(il, &il->txq[0]);
                il_txq_update_write_ptr(il, &il->txq[1]);
                il_txq_update_write_ptr(il, &il->txq[2]);
                il_txq_update_write_ptr(il, &il->txq[3]);
                il_txq_update_write_ptr(il, &il->txq[4]);
-               il_txq_update_write_ptr(il, &il->txq[5]);
+               spin_unlock_irqrestore(&il->lock, flags);
 
                il->isr_stats.wakeup++;
                handled |= CSR_INT_BIT_WAKEUP;
index 43f488a8cda21790a646dcd4efa4ffd04d445c96..888ad5c74639e351a3727c8b934a68f7969849e5 100644 (file)
@@ -92,7 +92,6 @@ il4965_check_abort_status(struct il_priv *il, u8 frame_count, u32 status)
  * EEPROM
  */
 struct il_mod_params il4965_mod_params = {
-       .amsdu_size_8K = 1,
        .restart_fw = 1,
        /* the rest are 0 by default */
 };
@@ -4274,17 +4273,7 @@ il4965_rx_handle(struct il_priv *il)
                len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
                len += sizeof(u32);     /* account for status word */
 
-               /* Reclaim a command buffer only if this packet is a response
-                *   to a (driver-originated) command.
-                * If the packet (e.g. Rx frame) originated from uCode,
-                *   there is no command buffer to reclaim.
-                * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
-                *   but apparently a few don't get set; catch them here. */
-               reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
-                   (pkt->hdr.cmd != N_RX_PHY) && (pkt->hdr.cmd != N_RX) &&
-                   (pkt->hdr.cmd != N_RX_MPDU) &&
-                   (pkt->hdr.cmd != N_COMPRESSED_BA) &&
-                   (pkt->hdr.cmd != N_STATS) && (pkt->hdr.cmd != C_TX);
+               reclaim = il_need_reclaim(il, pkt);
 
                /* Based on type of command response or notification,
                 *   handle those that need handling via function in
@@ -6876,6 +6865,6 @@ module_param_named(11n_disable, il4965_mod_params.disable_11n, int, S_IRUGO);
 MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
 module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int,
                   S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0 [disabled])");
 module_param_named(fw_restart, il4965_mod_params.restart_fw, int, S_IRUGO);
 MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
index 048421511988afb12892bc7f9951d07f90d5d85c..dd744135c9566fcc8bf9877c37ba19762bccb27c 100644 (file)
@@ -2270,7 +2270,8 @@ struct il_spectrum_notification {
  */
 #define IL_POWER_VEC_SIZE 5
 
-#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK        cpu_to_le16(BIT(0))
+#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK                cpu_to_le16(BIT(0))
+#define IL_POWER_SLEEP_OVER_DTIM_MSK           cpu_to_le16(BIT(2))
 #define IL_POWER_PCI_PM_MSK                    cpu_to_le16(BIT(3))
 
 struct il3945_powertable_cmd {
index 02e8233ccf29865e988eed0be9036c7dfc2179c8..4f42174d999412102e273744fc39ff692b9a9234 100644 (file)
@@ -1078,29 +1078,82 @@ EXPORT_SYMBOL(il_get_channel_info);
  * Setting power level allows the card to go to sleep when not busy.
  *
  * We calculate a sleep command based on the required latency, which
- * we get from mac80211. In order to handle thermal throttling, we can
- * also use pre-defined power levels.
+ * we get from mac80211.
  */
 
-/*
- * This defines the old power levels. They are still used by default
- * (level 1) and for thermal throttle (levels 3 through 5)
- */
-
-struct il_power_vec_entry {
-       struct il_powertable_cmd cmd;
-       u8 no_dtim;             /* number of skip dtim */
-};
+#define SLP_VEC(X0, X1, X2, X3, X4) { \
+               cpu_to_le32(X0), \
+               cpu_to_le32(X1), \
+               cpu_to_le32(X2), \
+               cpu_to_le32(X3), \
+               cpu_to_le32(X4)  \
+}
 
 static void
-il_power_sleep_cam_cmd(struct il_priv *il, struct il_powertable_cmd *cmd)
+il_build_powertable_cmd(struct il_priv *il, struct il_powertable_cmd *cmd)
 {
+       const __le32 interval[3][IL_POWER_VEC_SIZE] = {
+               SLP_VEC(2, 2, 4, 6, 0xFF),
+               SLP_VEC(2, 4, 7, 10, 10),
+               SLP_VEC(4, 7, 10, 10, 0xFF)
+       };
+       int i, dtim_period, no_dtim;
+       u32 max_sleep;
+       bool skip;
+
        memset(cmd, 0, sizeof(*cmd));
 
        if (il->power_data.pci_pm)
                cmd->flags |= IL_POWER_PCI_PM_MSK;
 
-       D_POWER("Sleep command for CAM\n");
+       /* if no Power Save, we are done */
+       if (il->power_data.ps_disabled)
+               return;
+
+       cmd->flags = IL_POWER_DRIVER_ALLOW_SLEEP_MSK;
+       cmd->keep_alive_seconds = 0;
+       cmd->debug_flags = 0;
+       cmd->rx_data_timeout = cpu_to_le32(25 * 1024);
+       cmd->tx_data_timeout = cpu_to_le32(25 * 1024);
+       cmd->keep_alive_beacons = 0;
+
+       dtim_period = il->vif ? il->vif->bss_conf.dtim_period : 0;
+
+       if (dtim_period <= 2) {
+               memcpy(cmd->sleep_interval, interval[0], sizeof(interval[0]));
+               no_dtim = 2;
+       } else if (dtim_period <= 10) {
+               memcpy(cmd->sleep_interval, interval[1], sizeof(interval[1]));
+               no_dtim = 2;
+       } else {
+               memcpy(cmd->sleep_interval, interval[2], sizeof(interval[2]));
+               no_dtim = 0;
+       }
+
+       if (dtim_period == 0) {
+               dtim_period = 1;
+               skip = false;
+       } else {
+               skip = !!no_dtim;
+       }
+
+       if (skip) {
+               __le32 tmp = cmd->sleep_interval[IL_POWER_VEC_SIZE - 1];
+
+               max_sleep = le32_to_cpu(tmp);
+               if (max_sleep == 0xFF)
+                       max_sleep = dtim_period * (skip + 1);
+               else if (max_sleep >  dtim_period)
+                       max_sleep = (max_sleep / dtim_period) * dtim_period;
+               cmd->flags |= IL_POWER_SLEEP_OVER_DTIM_MSK;
+       } else {
+               max_sleep = dtim_period;
+               cmd->flags &= ~IL_POWER_SLEEP_OVER_DTIM_MSK;
+       }
+
+       for (i = 0; i < IL_POWER_VEC_SIZE; i++)
+               if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+                       cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
 }
 
 static int
@@ -1173,7 +1226,8 @@ il_power_update_mode(struct il_priv *il, bool force)
 {
        struct il_powertable_cmd cmd;
 
-       il_power_sleep_cam_cmd(il, &cmd);
+       il_build_powertable_cmd(il, &cmd);
+
        return il_power_set_mode(il, &cmd, force);
 }
 EXPORT_SYMBOL(il_power_update_mode);
@@ -5081,6 +5135,7 @@ set_ch_out:
        }
 
        if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) {
+               il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS);
                ret = il_power_update_mode(il, false);
                if (ret)
                        D_MAC80211("Error setting sleep level\n");
index ad123d66ab6c5c13e2bd120df7b3c2b412d1400a..dfb13c70efe83ea8415f93ef2dad9c97a0cb6891 100644 (file)
@@ -1123,6 +1123,7 @@ struct il_power_mgr {
        struct il_powertable_cmd sleep_cmd_next;
        int debug_sleep_level_override;
        bool pci_pm;
+       bool ps_disabled;
 };
 
 struct il_priv {
@@ -1597,7 +1598,7 @@ struct il_mod_params {
        int disable_hw_scan;    /* def: 0 = use h/w scan */
        int num_of_queues;      /* def: HW dependent */
        int disable_11n;        /* def: 0 = 11n capabilities enabled */
-       int amsdu_size_8K;      /* def: 1 = enable 8K amsdu size */
+       int amsdu_size_8K;      /* def: 0 = disable 8K amsdu size */
        int antenna;            /* def: 0 = both antennas (use diversity) */
        int restart_fw;         /* def: 1 = restart firmware */
 };
@@ -1978,6 +1979,20 @@ void il_wr_prph(struct il_priv *il, u32 addr, u32 val);
 u32 il_read_targ_mem(struct il_priv *il, u32 addr);
 void il_write_targ_mem(struct il_priv *il, u32 addr, u32 val);
 
+static inline bool il_need_reclaim(struct il_priv *il, struct il_rx_pkt *pkt)
+{
+       /* Reclaim a command buffer only if this packet is a response
+        * to a (driver-originated) command. If the packet (e.g. Rx frame)
+        * originated from uCode, there is no command buffer to reclaim.
+        * Ucode should set SEQ_RX_FRAME bit if ucode-originated, but
+        * apparently a few don't get set; catch them here.
+        */
+       return !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+              pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX &&
+              pkt->hdr.cmd != N_RX_PHY && pkt->hdr.cmd != N_RX &&
+              pkt->hdr.cmd != N_RX_MPDU && pkt->hdr.cmd != N_COMPRESSED_BA;
+}
+
 static inline void
 _il_write8(struct il_priv *il, u32 ofs, u8 val)
 {
index 562772d851021e390575868ece4f3fbf04068ede..c160dad03037bd01399a8747096a3653ee67cd3a 100644 (file)
@@ -109,7 +109,7 @@ extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg;
 
 struct iwl_ucode_capabilities;
 
-extern struct ieee80211_ops iwlagn_hw_ops;
+extern const struct ieee80211_ops iwlagn_hw_ops;
 
 static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
 {
@@ -480,7 +480,7 @@ do {                                                                        \
 } while (0)
 #endif                         /* CONFIG_IWLWIFI_DEBUG */
 
-extern const char *iwl_dvm_cmd_strings[REPLY_MAX];
+extern const char *const iwl_dvm_cmd_strings[REPLY_MAX];
 
 static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
 {
index 7b140e487deb8da42a19d669e4428830516470c6..758c54eeb206718f8077aa2686304ea1a1e4c9bb 100644 (file)
@@ -317,7 +317,7 @@ static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
        .nrg_th_cca = 62,
 };
 
-static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+static const struct iwl_sensitivity_ranges iwl5150_sensitivity = {
        .min_nrg_cck = 95,
        .auto_corr_min_ofdm = 90,
        .auto_corr_min_ofdm_mrc = 170,
index 73086c1629ca13be4e359badffd927a3fee43847..dd55c9cf7ba80376ef3ae507b434e79d6dd1cca4 100644 (file)
@@ -1582,7 +1582,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
-struct ieee80211_ops iwlagn_hw_ops = {
+const struct ieee80211_ops iwlagn_hw_ops = {
        .tx = iwlagn_mac_tx,
        .start = iwlagn_mac_start,
        .stop = iwlagn_mac_stop,
index 7a1bc1c547e17ea3e35c47b1070c174c9268c9d6..cd8377346aff0c2936a6f0ee773ae8fd33042025 100644 (file)
@@ -39,7 +39,7 @@
 
 #define IWL_CMD_ENTRY(x) [x] = #x
 
-const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
+const char *const iwl_dvm_cmd_strings[REPLY_MAX] = {
        IWL_CMD_ENTRY(REPLY_ALIVE),
        IWL_CMD_ENTRY(REPLY_ERROR),
        IWL_CMD_ENTRY(REPLY_ECHO),
index c0d070c5df5ed73e14a64e141d6a7d2f2a3133b6..9cdd91cdf661825604e9ae8c89649213667b0b0e 100644 (file)
@@ -590,6 +590,7 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
                        sizeof(priv->tid_data[sta_id][tid]));
 
        priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+       priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
 
        priv->num_stations--;
 
index a6839dfcb82dd75029c1e377bbebb078464a8792..398dd096674cf17bd8112e8e7d06ad4ce57427f0 100644 (file)
@@ -1291,8 +1291,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
        struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
        struct iwl_ht_agg *agg;
        struct sk_buff_head reclaimed_skbs;
-       struct ieee80211_tx_info *info;
-       struct ieee80211_hdr *hdr;
        struct sk_buff *skb;
        int sta_id;
        int tid;
@@ -1379,22 +1377,28 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
        freed = 0;
 
        skb_queue_walk(&reclaimed_skbs, skb) {
-               hdr = (struct ieee80211_hdr *)skb->data;
+               struct ieee80211_hdr *hdr = (void *)skb->data;
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
                if (ieee80211_is_data_qos(hdr->frame_control))
                        freed++;
                else
                        WARN_ON_ONCE(1);
 
-               info = IEEE80211_SKB_CB(skb);
                iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
 
+               memset(&info->status, 0, sizeof(info->status));
+               /* Packet was transmitted successfully, failures come as single
+                * frames because before failing a frame the firmware transmits
+                * it without aggregation at least once.
+                */
+               info->flags |= IEEE80211_TX_STAT_ACK;
+
                if (freed == 1) {
                        /* this is the first skb we deliver in this batch */
                        /* put the rate scaling data there */
                        info = IEEE80211_SKB_CB(skb);
                        memset(&info->status, 0, sizeof(info->status));
-                       info->flags |= IEEE80211_TX_STAT_ACK;
                        info->flags |= IEEE80211_TX_STAT_AMPDU;
                        info->status.ampdu_ack_len = ba_resp->txed_2_done;
                        info->status.ampdu_len = ba_resp->txed;
index bcfdcfb4485e70c69c26f448fd3e745f5da3fac2..0a3e841b44a9ebe81cbd40b0313e8cafcc355f3a 100644 (file)
@@ -404,6 +404,38 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data)
        return 0;
 }
 
+static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data,
+                                  struct iwl_ucode_capabilities *capa)
+{
+       const struct iwl_ucode_api *ucode_api = (void *)data;
+       u32 api_index = le32_to_cpu(ucode_api->api_index);
+
+       if (api_index >= IWL_API_ARRAY_SIZE) {
+               IWL_ERR(drv, "api_index larger than supported by driver\n");
+               return -EINVAL;
+       }
+
+       capa->api[api_index] = le32_to_cpu(ucode_api->api_flags);
+
+       return 0;
+}
+
+static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data,
+                                     struct iwl_ucode_capabilities *capa)
+{
+       const struct iwl_ucode_capa *ucode_capa = (void *)data;
+       u32 api_index = le32_to_cpu(ucode_capa->api_index);
+
+       if (api_index >= IWL_CAPABILITIES_ARRAY_SIZE) {
+               IWL_ERR(drv, "api_index larger than supported by driver\n");
+               return -EINVAL;
+       }
+
+       capa->capa[api_index] = le32_to_cpu(ucode_capa->api_capa);
+
+       return 0;
+}
+
 static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
                                    const struct firmware *ucode_raw,
                                    struct iwl_firmware_pieces *pieces)
@@ -638,6 +670,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                         */
                        capa->flags = le32_to_cpup((__le32 *)tlv_data);
                        break;
+               case IWL_UCODE_TLV_API_CHANGES_SET:
+                       if (tlv_len != sizeof(struct iwl_ucode_api))
+                               goto invalid_tlv_len;
+                       if (iwl_set_ucode_api_flags(drv, tlv_data, capa))
+                               goto tlv_error;
+                       break;
+               case IWL_UCODE_TLV_ENABLED_CAPABILITIES:
+                       if (tlv_len != sizeof(struct iwl_ucode_capa))
+                               goto invalid_tlv_len;
+                       if (iwl_set_ucode_capabilities(drv, tlv_data, capa))
+                               goto tlv_error;
+                       break;
                case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
                        if (tlv_len != sizeof(u32))
                                goto invalid_tlv_len;
@@ -728,6 +772,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                        if (tlv_len != sizeof(u32))
                                goto invalid_tlv_len;
                        drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
+                       drv->fw.valid_tx_ant = (drv->fw.phy_config &
+                                               FW_PHY_CFG_TX_CHAIN) >>
+                                               FW_PHY_CFG_TX_CHAIN_POS;
+                       drv->fw.valid_rx_ant = (drv->fw.phy_config &
+                                               FW_PHY_CFG_RX_CHAIN) >>
+                                               FW_PHY_CFG_RX_CHAIN_POS;
                        break;
                 case IWL_UCODE_TLV_SECURE_SEC_RT:
                        iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
@@ -1301,8 +1351,7 @@ MODULE_PARM_DESC(antenna_coupling,
 
 module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
 MODULE_PARM_DESC(wd_disable,
-               "Disable stuck queue watchdog timer 0=system default, "
-               "1=disable, 2=enable (default: 0)");
+               "Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)");
 
 module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
 MODULE_PARM_DESC(nvm_file, "NVM file name");
index 592c01e11013c3ce74264f49951c29eff84610c4..3c72cb710b0cb8dc4b4d7d7be478488acc569029 100644 (file)
 #define DRV_COPYRIGHT  "Copyright(c) 2003- 2014 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
+/* radio config bits (actual values from NVM definition) */
+#define NVM_RF_CFG_DASH_MSK(x)   (x & 0x3)         /* bits 0-1   */
+#define NVM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
+#define NVM_RF_CFG_TYPE_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
+#define NVM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
+#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
+#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
+
+#define NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(x)   (x & 0xF)
+#define NVM_RF_CFG_DASH_MSK_FAMILY_8000(x)   ((x >> 4) & 0xF)
+#define NVM_RF_CFG_STEP_MSK_FAMILY_8000(x)   ((x >> 8) & 0xF)
+#define NVM_RF_CFG_TYPE_MSK_FAMILY_8000(x)   ((x >> 12) & 0xFFF)
+#define NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(x) ((x >> 24) & 0xF)
+#define NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(x) ((x >> 28) & 0xF)
 
 /**
  * DOC: Driver system flows - drv component
index e3c7deafabe6e71abd012751a59655aa977ef980..f0548b8a64b072a1a58b80e6d6d5cc7b9d00df59 100644 (file)
@@ -81,16 +81,17 @@ struct iwl_nvm_data {
        bool sku_cap_band_24GHz_enable;
        bool sku_cap_band_52GHz_enable;
        bool sku_cap_11n_enable;
+       bool sku_cap_11ac_enable;
        bool sku_cap_amt_enable;
        bool sku_cap_ipan_enable;
 
-       u8 radio_cfg_type;
+       u16 radio_cfg_type;
        u8 radio_cfg_step;
        u8 radio_cfg_dash;
        u8 radio_cfg_pnum;
        u8 valid_tx_ant, valid_rx_ant;
 
-       u16 nvm_version;
+       u32 nvm_version;
        s8 max_tx_pwr_half_dbm;
 
        struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
index 88e2d6eb569f4f23ba7696178ffe96135dfdb508..b45e576a4b57feb01982edb99191a65a3ae38bca 100644 (file)
@@ -126,6 +126,8 @@ enum iwl_ucode_tlv_type {
        IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
        IWL_UCODE_TLV_NUM_OF_CPU        = 27,
        IWL_UCODE_TLV_CSCHEME           = 28,
+       IWL_UCODE_TLV_API_CHANGES_SET   = 29,
+       IWL_UCODE_TLV_ENABLED_CAPABILITIES      = 30,
 };
 
 struct iwl_ucode_tlv {
@@ -158,4 +160,19 @@ struct iwl_tlv_ucode_header {
        u8 data[0];
 };
 
+/*
+ * ucode TLVs
+ *
+ * ability to get extension for: flags & capabilities from ucode binaries files
+ */
+struct iwl_ucode_api {
+       __le32 api_index;
+       __le32 api_flags;
+} __packed;
+
+struct iwl_ucode_capa {
+       __le32 api_index;
+       __le32 api_capa;
+} __packed;
+
 #endif  /* __iwl_fw_file_h__ */
index f80ba586c2535c64a02866d8d87efb4f21b1d166..f04ff871dc6d5f4a7bc52f6651bb06549c473e0c 100644 (file)
@@ -92,8 +92,8 @@
  * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
  * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
  *     containing CAM (Continuous Active Mode) indication.
- * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
- *     single bound interface).
+ * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and
+ *     P2P client interfaces simultaneously if they are in different bindings.
  * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
  * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
  * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
@@ -118,7 +118,7 @@ enum iwl_ucode_tlv_flag {
        IWL_UCODE_TLV_FLAGS_SCHED_SCAN          = BIT(17),
        IWL_UCODE_TLV_FLAGS_STA_KEY_CMD         = BIT(19),
        IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD       = BIT(20),
-       IWL_UCODE_TLV_FLAGS_P2P_PS              = BIT(21),
+       IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM      = BIT(22),
        IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT       = BIT(24),
        IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD        = BIT(26),
        IWL_UCODE_TLV_FLAGS_BCAST_FILTERING     = BIT(29),
@@ -165,11 +165,15 @@ enum iwl_ucode_sec {
  * just an offset to the HW address.
  */
 #define IWL_UCODE_SECTION_MAX 12
+#define IWL_API_ARRAY_SIZE     1
+#define IWL_CAPABILITIES_ARRAY_SIZE    1
 
 struct iwl_ucode_capabilities {
        u32 max_probe_length;
        u32 standard_phy_calibration_size;
        u32 flags;
+       u32 api[IWL_API_ARRAY_SIZE];
+       u32 capa[IWL_CAPABILITIES_ARRAY_SIZE];
 };
 
 /* one for each uCode image (inst/data, init/runtime/wowlan) */
@@ -288,22 +292,12 @@ struct iwl_fw {
 
        struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX];
        u32 phy_config;
+       u8 valid_tx_ant;
+       u8 valid_rx_ant;
 
        bool mvm_fw;
 
        struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
 };
 
-static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
-{
-       return (fw->phy_config & FW_PHY_CFG_TX_CHAIN) >>
-               FW_PHY_CFG_TX_CHAIN_POS;
-}
-
-static inline u8 iwl_fw_valid_rx_ant(const struct iwl_fw *fw)
-{
-       return (fw->phy_config & FW_PHY_CFG_RX_CHAIN) >>
-               FW_PHY_CFG_RX_CHAIN_POS;
-}
-
 #endif  /* __iwl_fw_h__ */
index b29075c3da8e2e65e8c621c89fda3b5f9b586e79..d994317db85b72cbfc11f602e2d414efc54233b1 100644 (file)
@@ -96,7 +96,7 @@ enum iwl_disable_11n {
  *     use IWL_[DIS,EN]ABLE_HT_* constants
  * @amsdu_size_8K: enable 8K amsdu size, default = 0
  * @restart_fw: restart firmware, default = 1
- * @wd_disable: enable stuck queue check, default = 0
+ * @wd_disable: disable stuck queue check, default = 1
  * @bt_coex_active: enable bt coex, default = true
  * @led_mode: system default, default = 0
  * @power_save: disable power save, default = false
index 53b9cad504779fb4712e8b3e4da893d3d61b13fe..2f962ec0b75065b7387787a9444383c7e38094d7 100644 (file)
@@ -71,7 +71,7 @@ enum wkp_nvm_offsets {
        /* NVM HW-Section offset (in words) definitions */
        HW_ADDR = 0x15,
 
-/* NVM SW-Section offset (in words) definitions */
+       /* NVM SW-Section offset (in words) definitions */
        NVM_SW_SECTION = 0x1C0,
        NVM_VERSION = 0,
        RADIO_CFG = 1,
@@ -79,11 +79,32 @@ enum wkp_nvm_offsets {
        N_HW_ADDRS = 3,
        NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
 
-/* NVM calibration section offset (in words) definitions */
+       /* NVM calibration section offset (in words) definitions */
        NVM_CALIB_SECTION = 0x2B8,
        XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
 };
 
+enum family_8000_nvm_offsets {
+       /* NVM HW-Section offset (in words) definitions */
+       HW_ADDR0_FAMILY_8000 = 0x12,
+       HW_ADDR1_FAMILY_8000 = 0x16,
+       MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1,
+
+       /* NVM SW-Section offset (in words) definitions */
+       NVM_SW_SECTION_FAMILY_8000 = 0x1C0,
+       NVM_VERSION_FAMILY_8000 = 0,
+       RADIO_CFG_FAMILY_8000 = 2,
+       SKU_FAMILY_8000 = 4,
+       N_HW_ADDRS_FAMILY_8000 = 5,
+
+       /* NVM REGULATORY -Section offset (in words) definitions */
+       NVM_CHANNELS_FAMILY_8000 = 0,
+
+       /* NVM calibration section offset (in words) definitions */
+       NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8,
+       XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000
+};
+
 /* SKU Capabilities (actual values from NVM definition) */
 enum nvm_sku_bits {
        NVM_SKU_CAP_BAND_24GHZ  = BIT(0),
@@ -92,14 +113,6 @@ enum nvm_sku_bits {
        NVM_SKU_CAP_11AC_ENABLE = BIT(3),
 };
 
-/* radio config bits (actual values from NVM definition) */
-#define NVM_RF_CFG_DASH_MSK(x)   (x & 0x3)         /* bits 0-1   */
-#define NVM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
-#define NVM_RF_CFG_TYPE_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
-#define NVM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
-#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
-#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
-
 /*
  * These are the channel numbers in the order that they are stored in the NVM
  */
@@ -112,7 +125,17 @@ static const u8 iwl_nvm_channels[] = {
        149, 153, 157, 161, 165
 };
 
+static const u8 iwl_nvm_channels_family_8000[] = {
+       /* 2.4 GHz */
+       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+       /* 5 GHz */
+       36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
+       96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
+       149, 153, 157, 161, 165, 169, 173, 177, 181
+};
+
 #define IWL_NUM_CHANNELS       ARRAY_SIZE(iwl_nvm_channels)
+#define IWL_NUM_CHANNELS_FAMILY_8000   ARRAY_SIZE(iwl_nvm_channels_family_8000)
 #define NUM_2GHZ_CHANNELS      14
 #define FIRST_2GHZ_HT_MINUS    5
 #define LAST_2GHZ_HT_PLUS      9
@@ -179,8 +202,18 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
        struct ieee80211_channel *channel;
        u16 ch_flags;
        bool is_5ghz;
+       int num_of_ch;
+       const u8 *nvm_chan;
+
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+               num_of_ch = IWL_NUM_CHANNELS;
+               nvm_chan = &iwl_nvm_channels[0];
+       } else {
+               num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
+               nvm_chan = &iwl_nvm_channels_family_8000[0];
+       }
 
-       for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) {
+       for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
                ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 
                if (ch_idx >= NUM_2GHZ_CHANNELS &&
@@ -190,7 +223,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                if (!(ch_flags & NVM_CHANNEL_VALID)) {
                        IWL_DEBUG_EEPROM(dev,
                                         "Ch. %d Flags %x [%sGHz] - No traffic\n",
-                                        iwl_nvm_channels[ch_idx],
+                                        nvm_chan[ch_idx],
                                         ch_flags,
                                         (ch_idx >= NUM_2GHZ_CHANNELS) ?
                                         "5.2" : "2.4");
@@ -200,7 +233,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                channel = &data->channels[n_channels];
                n_channels++;
 
-               channel->hw_value = iwl_nvm_channels[ch_idx];
+               channel->hw_value = nvm_chan[ch_idx];
                channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
                                IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
                channel->center_freq =
@@ -211,11 +244,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                channel->flags = IEEE80211_CHAN_NO_HT40;
                if (ch_idx < NUM_2GHZ_CHANNELS &&
                    (ch_flags & NVM_CHANNEL_40MHZ)) {
-                       if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS)
+                       if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
                                channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
-                       if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS)
+                       if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
                                channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
-               } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT &&
+               } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT &&
                           (ch_flags & NVM_CHANNEL_40MHZ)) {
                        if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
                                channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
@@ -307,14 +340,23 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
 }
 
 static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
-                           struct iwl_nvm_data *data, const __le16 *nvm_sw,
-                           bool enable_vht, u8 tx_chains, u8 rx_chains)
+                           struct iwl_nvm_data *data,
+                           const __le16 *ch_section, bool enable_vht,
+                           u8 tx_chains, u8 rx_chains)
 {
-       int n_channels = iwl_init_channel_map(dev, cfg, data,
-                       &nvm_sw[NVM_CHANNELS]);
+       int n_channels;
        int n_used = 0;
        struct ieee80211_supported_band *sband;
 
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+               n_channels = iwl_init_channel_map(
+                               dev, cfg, data,
+                               &ch_section[NVM_CHANNELS]);
+       else
+               n_channels = iwl_init_channel_map(
+                               dev, cfg, data,
+                               &ch_section[NVM_CHANNELS_FAMILY_8000]);
+
        sband = &data->bands[IEEE80211_BAND_2GHZ];
        sband->band = IEEE80211_BAND_2GHZ;
        sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
@@ -340,67 +382,150 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
                            n_used, n_channels);
 }
 
+static int iwl_get_sku(const struct iwl_cfg *cfg,
+                      const __le16 *nvm_sw)
+{
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+               return le16_to_cpup(nvm_sw + SKU);
+       else
+               return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000));
+}
+
+static int iwl_get_nvm_version(const struct iwl_cfg *cfg,
+                              const __le16 *nvm_sw)
+{
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+               return le16_to_cpup(nvm_sw + NVM_VERSION);
+       else
+               return le32_to_cpup((__le32 *)(nvm_sw +
+                                              NVM_VERSION_FAMILY_8000));
+}
+
+static int iwl_get_radio_cfg(const struct iwl_cfg *cfg,
+                            const __le16 *nvm_sw)
+{
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+               return le16_to_cpup(nvm_sw + RADIO_CFG);
+       else
+               return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000));
+}
+
+#define N_HW_ADDRS_MASK_FAMILY_8000    0xF
+static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg,
+                             const __le16 *nvm_sw)
+{
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+               return le16_to_cpup(nvm_sw + N_HW_ADDRS);
+       else
+               return le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000))
+                      & N_HW_ADDRS_MASK_FAMILY_8000;
+}
+
+static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
+                             struct iwl_nvm_data *data,
+                             u32 radio_cfg)
+{
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+               data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
+               data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
+               data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
+               data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
+               return;
+       }
+
+       /* set the radio configuration for family 8000 */
+       data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg);
+       data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg);
+       data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg);
+       data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg);
+}
+
+static void iwl_set_hw_address(const struct iwl_cfg *cfg,
+                              struct iwl_nvm_data *data,
+                              const __le16 *nvm_sec)
+{
+       u8 hw_addr[ETH_ALEN];
+
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+               memcpy(hw_addr, nvm_sec + HW_ADDR, ETH_ALEN);
+       else
+               memcpy(hw_addr, nvm_sec + MAC_ADDRESS_OVERRIDE_FAMILY_8000,
+                      ETH_ALEN);
+
+       /* The byte order is little endian 16 bit, meaning 214365 */
+       data->hw_addr[0] = hw_addr[1];
+       data->hw_addr[1] = hw_addr[0];
+       data->hw_addr[2] = hw_addr[3];
+       data->hw_addr[3] = hw_addr[2];
+       data->hw_addr[4] = hw_addr[5];
+       data->hw_addr[5] = hw_addr[4];
+}
+
 struct iwl_nvm_data *
 iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
                   const __le16 *nvm_hw, const __le16 *nvm_sw,
-                  const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains)
+                  const __le16 *nvm_calib, const __le16 *regulatory,
+                  const __le16 *mac_override, u8 tx_chains, u8 rx_chains)
 {
        struct iwl_nvm_data *data;
-       u8 hw_addr[ETH_ALEN];
-       u16 radio_cfg, sku;
-
-       data = kzalloc(sizeof(*data) +
-                      sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
-                      GFP_KERNEL);
+       u32 sku;
+       u32 radio_cfg;
+
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
+               data = kzalloc(sizeof(*data) +
+                              sizeof(struct ieee80211_channel) *
+                              IWL_NUM_CHANNELS,
+                              GFP_KERNEL);
+       else
+               data = kzalloc(sizeof(*data) +
+                              sizeof(struct ieee80211_channel) *
+                              IWL_NUM_CHANNELS_FAMILY_8000,
+                              GFP_KERNEL);
        if (!data)
                return NULL;
 
-       data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION);
+       data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw);
 
-       radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG);
-       data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
-       data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
-       data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
-       data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
-       data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
-       data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
+       radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw);
+       iwl_set_radio_cfg(cfg, data, radio_cfg);
 
-       sku = le16_to_cpup(nvm_sw + SKU);
+       sku = iwl_get_sku(cfg, nvm_sw);
        data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
        data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
        data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
+       data->sku_cap_11ac_enable = sku & NVM_SKU_CAP_11AC_ENABLE;
        if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
                data->sku_cap_11n_enable = false;
 
-       /* check overrides (some devices have wrong NVM) */
-       if (cfg->valid_tx_ant)
-               data->valid_tx_ant = cfg->valid_tx_ant;
-       if (cfg->valid_rx_ant)
-               data->valid_rx_ant = cfg->valid_rx_ant;
+       data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
 
-       if (!data->valid_tx_ant || !data->valid_rx_ant) {
-               IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
-                           data->valid_tx_ant, data->valid_rx_ant);
-               kfree(data);
-               return NULL;
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+               /* Checking for required sections */
+               if (!nvm_calib) {
+                       IWL_ERR_DEV(dev,
+                                   "Can't parse empty Calib NVM sections\n");
+                       kfree(data);
+                       return NULL;
+               }
+               /* in family 8000 Xtal calibration values moved to OTP */
+               data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
+               data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
        }
 
-       data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS);
+       if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+               iwl_set_hw_address(cfg, data, nvm_hw);
 
-       data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
-       data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
+               iwl_init_sbands(dev, cfg, data, nvm_sw,
+                               sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
+                               rx_chains);
+       } else {
+               /* MAC address in family 8000 */
+               iwl_set_hw_address(cfg, data, mac_override);
 
-       /* The byte order is little endian 16 bit, meaning 214365 */
-       memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN);
-       data->hw_addr[0] = hw_addr[1];
-       data->hw_addr[1] = hw_addr[0];
-       data->hw_addr[2] = hw_addr[3];
-       data->hw_addr[3] = hw_addr[2];
-       data->hw_addr[4] = hw_addr[5];
-       data->hw_addr[5] = hw_addr[4];
-
-       iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE,
-                       tx_chains, rx_chains);
+               iwl_init_sbands(dev, cfg, data, regulatory,
+                               sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
+                               rx_chains);
+       }
 
        data->calib_version = 255;
 
index 0c4399aba8c6bfcbbee990f964296543563dfbe1..c9c45a39d212c2516433bdce81c74373460383ab 100644 (file)
@@ -75,6 +75,7 @@
 struct iwl_nvm_data *
 iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
                   const __le16 *nvm_hw, const __le16 *nvm_sw,
-                  const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains);
+                  const __le16 *nvm_calib, const __le16 *regulatory,
+                  const __le16 *mac_override, u8 tx_chains, u8 rx_chains);
 
 #endif /* __iwl_nvm_parse_h__ */
index 7b19274b550f2bef5c0dbb9c5b4d4d933dc81d5e..8cdb0dd618a6fdfcc8d57095e41974e6e22984ab 100644 (file)
@@ -393,7 +393,7 @@ struct iwl_trans_config {
        bool rx_buf_size_8k;
        bool bc_table_dword;
        unsigned int queue_watchdog_timeout;
-       const char **command_names;
+       const char *const *command_names;
 };
 
 struct iwl_trans;
index 38a54a3fde3425ee0dd6b301a09c06f1c330d775..2aa3ee93c68ed7c9a9e2b93b00e512ac4003f71f 100644 (file)
@@ -906,8 +906,11 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        lockdep_assert_held(&mvm->mutex);
 
-       /* Rssi update while not associated ?! */
-       if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT))
+       /*
+        * Rssi update while not associated - can happen since the statistics
+        * are handled asynchronously
+        */
+       if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
                return;
 
        /* No BT - reports should be disabled */
index 29b4396018b1d45c81afe3050a3289cad9598b53..f64e972191eb567f3fdf7cb94072237a8c0f1d7d 100644 (file)
@@ -591,7 +591,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
            iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
            ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
             (vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
-             mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)))
+             mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)))
                MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
                                         S_IRUSR);
 
index 6853e5efe522322d648a3431df1a7900cd527524..e0ff43ed24829c78024a8b3db0a72a9511f5101b 100644 (file)
@@ -531,6 +531,76 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
 }
 #undef PRINT_STAT_LE32
 
+static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
+                                         char __user *user_buf, size_t count,
+                                         loff_t *ppos,
+                                         struct iwl_mvm_frame_stats *stats)
+{
+       char *buff;
+       int pos = 0, idx, i;
+       int ret;
+       size_t bufsz = 1024;
+
+       buff = kmalloc(bufsz, GFP_KERNEL);
+       if (!buff)
+               return -ENOMEM;
+
+       spin_lock_bh(&mvm->drv_stats_lock);
+       pos += scnprintf(buff + pos, bufsz - pos,
+                        "Legacy/HT/VHT\t:\t%d/%d/%d\n",
+                        stats->legacy_frames,
+                        stats->ht_frames,
+                        stats->vht_frames);
+       pos += scnprintf(buff + pos, bufsz - pos, "20/40/80\t:\t%d/%d/%d\n",
+                        stats->bw_20_frames,
+                        stats->bw_40_frames,
+                        stats->bw_80_frames);
+       pos += scnprintf(buff + pos, bufsz - pos, "NGI/SGI\t\t:\t%d/%d\n",
+                        stats->ngi_frames,
+                        stats->sgi_frames);
+       pos += scnprintf(buff + pos, bufsz - pos, "SISO/MIMO2\t:\t%d/%d\n",
+                        stats->siso_frames,
+                        stats->mimo2_frames);
+       pos += scnprintf(buff + pos, bufsz - pos, "FAIL/SCSS\t:\t%d/%d\n",
+                        stats->fail_frames,
+                        stats->success_frames);
+       pos += scnprintf(buff + pos, bufsz - pos, "MPDUs agg\t:\t%d\n",
+                        stats->agg_frames);
+       pos += scnprintf(buff + pos, bufsz - pos, "A-MPDUs\t\t:\t%d\n",
+                        stats->ampdu_count);
+       pos += scnprintf(buff + pos, bufsz - pos, "Avg MPDUs/A-MPDU:\t%d\n",
+                        stats->ampdu_count > 0 ?
+                        (stats->agg_frames / stats->ampdu_count) : 0);
+
+       pos += scnprintf(buff + pos, bufsz - pos, "Last Rates\n");
+
+       idx = stats->last_frame_idx - 1;
+       for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) {
+               idx = (idx + 1) % ARRAY_SIZE(stats->last_rates);
+               if (stats->last_rates[idx] == 0)
+                       continue;
+               pos += scnprintf(buff + pos, bufsz - pos, "Rate[%d]: ",
+                                (int)(ARRAY_SIZE(stats->last_rates) - i));
+               pos += rs_pretty_print_rate(buff + pos, stats->last_rates[idx]);
+       }
+       spin_unlock_bh(&mvm->drv_stats_lock);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos);
+       kfree(buff);
+
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file,
+                                          char __user *user_buf, size_t count,
+                                          loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+
+       return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos,
+                                         &mvm->drv_rx_stats);
+}
+
 static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
                                          size_t count, loff_t *ppos)
 {
@@ -591,7 +661,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
                return -EINVAL;
        if (scan_rx_ant > ANT_ABC)
                return -EINVAL;
-       if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw))
+       if (scan_rx_ant & ~mvm->fw->valid_rx_ant)
                return -EINVAL;
 
        mvm->scan_rx_ant = scan_rx_ant;
@@ -907,6 +977,49 @@ static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
 #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
        MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
 
+static ssize_t
+iwl_dbgfs_prph_reg_read(struct file *file,
+                       char __user *user_buf,
+                       size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       int pos = 0;
+       char buf[32];
+       const size_t bufsz = sizeof(buf);
+
+       if (!mvm->dbgfs_prph_reg_addr)
+               return -EINVAL;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
+               mvm->dbgfs_prph_reg_addr,
+               iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t
+iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
+                        size_t count, loff_t *ppos)
+{
+       u8 args;
+       u32 value;
+
+       args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
+       /* if we only want to set the reg address - nothing more to do */
+       if (args == 1)
+               goto out;
+
+       /* otherwise, make sure we have both address and value */
+       if (args != 2)
+               return -EINVAL;
+
+       iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
+out:
+       return count;
+}
+
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
+
 /* Device wide debugfs entries */
 MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
 MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
@@ -916,6 +1029,7 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
 MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
 MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
+MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
 MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
 MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
@@ -947,10 +1061,12 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
                MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
                                     S_IRUSR | S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
+       MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
                             S_IWUSR | S_IRUSR);
+       MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
index 85057219cc43ff4c4edbd3e606a9254dae9772e5..39148b5bb33262596e1dea348c1ae32c9a2c9166 100644 (file)
@@ -257,7 +257,8 @@ enum {
 
 /* Bit 17-18: (0) SS, (1) SS*2 */
 #define RATE_MCS_STBC_POS              17
-#define RATE_MCS_STBC_MSK              (1 << RATE_MCS_STBC_POS)
+#define RATE_MCS_HT_STBC_MSK           (3 << RATE_MCS_STBC_POS)
+#define RATE_MCS_VHT_STBC_MSK          (1 << RATE_MCS_STBC_POS)
 
 /* Bit 19: (0) Beamforming is off, (1) Beamforming is on */
 #define RATE_MCS_BF_POS                        19
index a7c88f1402e991ae1a0691e64f50b2b5473a08a0..807fa525cafe9a18c1cf658b5d4256219ce2e6cc 100644 (file)
@@ -306,7 +306,6 @@ struct iwl_phy_cfg_cmd {
 #define PHY_CFG_RX_CHAIN_B     BIT(13)
 #define PHY_CFG_RX_CHAIN_C     BIT(14)
 
-#define NVM_MAX_NUM_SECTIONS   11
 
 /* Target of the NVM_ACCESS_CMD */
 enum {
@@ -318,8 +317,11 @@ enum {
 /* Section types for NVM_ACCESS_CMD */
 enum {
        NVM_SECTION_TYPE_SW = 1,
+       NVM_SECTION_TYPE_REGULATORY = 3,
        NVM_SECTION_TYPE_CALIBRATION = 4,
        NVM_SECTION_TYPE_PRODUCTION = 5,
+       NVM_SECTION_TYPE_MAC_OVERRIDE = 11,
+       NVM_MAX_NUM_SECTIONS = 12,
 };
 
 /**
@@ -710,6 +712,7 @@ enum {
        TE_V2_NOTIF_HOST_FRAG_END = BIT(5),
        TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6),
        TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7),
+       T2_V2_START_IMMEDIATELY = BIT(11),
 
        TE_V2_NOTIF_MSK = 0xff,
 
index bae75b308fc0332bb08fbd30d3b21ec9fec56ee5..7ce20062f32d443be34fe87865d91afd71a0a014 100644 (file)
@@ -130,7 +130,6 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
        } else {
                palive2 = (void *)pkt->data;
 
-               mvm->support_umac_log = true;
                mvm->error_event_table =
                        le32_to_cpu(palive2->error_event_table_ptr);
                mvm->log_event_table =
@@ -141,6 +140,9 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
 
                alive_data->valid = le16_to_cpu(palive2->status) ==
                                    IWL_ALIVE_STATUS_OK;
+               if (mvm->umac_error_event_table)
+                       mvm->support_umac_log = true;
+
                IWL_DEBUG_FW(mvm,
                             "Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
                             le16_to_cpu(palive2->status), palive2->ver_type,
@@ -320,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
        }
 
        /* Send TX valid antennas before triggering calibrations */
-       ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
+       ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
        if (ret)
                goto error;
 
@@ -356,8 +358,6 @@ out:
                                        GFP_KERNEL);
                if (!mvm->nvm_data)
                        return -ENOMEM;
-               mvm->nvm_data->valid_rx_ant = 1;
-               mvm->nvm_data->valid_tx_ant = 1;
                mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels;
                mvm->nvm_data->bands[0].n_channels = 1;
                mvm->nvm_data->bands[0].n_bitrates = 1;
@@ -369,8 +369,6 @@ out:
        return ret;
 }
 
-#define UCODE_CALIB_TIMEOUT    (2*HZ)
-
 int iwl_mvm_up(struct iwl_mvm *mvm)
 {
        int ret, i;
@@ -422,7 +420,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
 
-       ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
+       ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
        if (ret)
                goto error;
 
@@ -507,7 +505,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
                goto error;
        }
 
-       ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
+       ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
        if (ret)
                goto error;
 
index 5c21aabb40cbc3b2c59309d26ea53c920bff2c28..9ccec10bba166299cc91cf1706992937127d277a 100644 (file)
@@ -952,7 +952,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
                                             TX_CMD_FLG_TSF);
 
        mvm->mgmt_last_antenna_idx =
-               iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
+               iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
                                     mvm->mgmt_last_antenna_idx);
 
        beacon_cmd.tx.rate_n_flags =
index a49d1ef13f42eff9b368d2341113a81e9dbe28b3..c2ab6a3318cb702785d30368c53f7d0986be551d 100644 (file)
@@ -68,6 +68,7 @@
 #include <linux/ip.h>
 #include <linux/if_arp.h>
 #include <net/mac80211.h>
+#include <net/ieee80211_radiotap.h>
 #include <net/tcp.h>
 
 #include "iwl-op-mode.h"
@@ -280,6 +281,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 
        hw->queues = mvm->first_agg_queue;
        hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
+       hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
+                                   IEEE80211_RADIOTAP_MCS_HAVE_STBC;
+       hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC;
        hw->rate_control_algorithm = "iwl-mvm-rs";
 
        /*
@@ -1319,7 +1323,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
        mvmvif->ap_ibss_active = true;
 
        /* power updated needs to be done before quotas */
-       mvm->bound_vif_cnt++;
        iwl_mvm_power_update_mac(mvm, vif);
 
        ret = iwl_mvm_update_quotas(mvm, vif);
@@ -1338,7 +1341,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
        return 0;
 
 out_quota_failed:
-       mvm->bound_vif_cnt--;
        iwl_mvm_power_update_mac(mvm, vif);
        mvmvif->ap_ibss_active = false;
        iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
@@ -1375,7 +1377,6 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
        iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
        iwl_mvm_binding_remove_vif(mvm, vif);
 
-       mvm->bound_vif_cnt--;
        iwl_mvm_power_update_mac(mvm, vif);
 
        iwl_mvm_mac_ctxt_remove(mvm, vif);
@@ -1764,14 +1765,16 @@ out:
        return ret;
 }
 
-static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
-                                       struct ieee80211_vif *vif)
+static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 
        mutex_lock(&mvm->mutex);
        iwl_mvm_sched_scan_stop(mvm);
        mutex_unlock(&mvm->mutex);
+
+       return 0;
 }
 
 static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
@@ -2109,7 +2112,6 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
         * Power state must be updated before quotas,
         * otherwise fw will complain.
         */
-       mvm->bound_vif_cnt++;
        iwl_mvm_power_update_mac(mvm, vif);
 
        /* Setting the quota at this stage is only required for monitor
@@ -2127,7 +2129,6 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
 
  out_remove_binding:
        iwl_mvm_binding_remove_vif(mvm, vif);
-       mvm->bound_vif_cnt--;
        iwl_mvm_power_update_mac(mvm, vif);
  out_unlock:
        mutex_unlock(&mvm->mutex);
@@ -2160,7 +2161,6 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
        }
 
        iwl_mvm_binding_remove_vif(mvm, vif);
-       mvm->bound_vif_cnt--;
        iwl_mvm_power_update_mac(mvm, vif);
 
 out_unlock:
@@ -2251,7 +2251,7 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
 }
 #endif
 
-struct ieee80211_ops iwl_mvm_hw_ops = {
+const struct ieee80211_ops iwl_mvm_hw_ops = {
        .tx = iwl_mvm_mac_tx,
        .ampdu_action = iwl_mvm_mac_ampdu_action,
        .start = iwl_mvm_mac_start,
index ebea5f2e274150802a1ee19e1a51978ba9ef30a0..302cf779c1729e784a46f485b45dbf1b5305c418 100644 (file)
@@ -91,8 +91,7 @@ enum iwl_mvm_tx_fifo {
        IWL_MVM_TX_FIFO_MCAST = 5,
 };
 
-extern struct ieee80211_ops iwl_mvm_hw_ops;
-extern const struct iwl_mvm_power_ops pm_mac_ops;
+extern const struct ieee80211_ops iwl_mvm_hw_ops;
 
 /**
  * struct iwl_mvm_mod_params - module parameters for iwlmvm
@@ -151,7 +150,7 @@ enum iwl_power_scheme {
        IWL_POWER_SCHEME_LP
 };
 
-#define IWL_CONN_MAX_LISTEN_INTERVAL   70
+#define IWL_CONN_MAX_LISTEN_INTERVAL   10
 #define IWL_UAPSD_AC_INFO              (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
                                         IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
                                         IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
@@ -426,6 +425,28 @@ struct iwl_mvm_tt_mgmt {
        bool throttle;
 };
 
+#define IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES 8
+
+struct iwl_mvm_frame_stats {
+       u32 legacy_frames;
+       u32 ht_frames;
+       u32 vht_frames;
+       u32 bw_20_frames;
+       u32 bw_40_frames;
+       u32 bw_80_frames;
+       u32 bw_160_frames;
+       u32 sgi_frames;
+       u32 ngi_frames;
+       u32 siso_frames;
+       u32 mimo2_frames;
+       u32 agg_frames;
+       u32 ampdu_count;
+       u32 success_frames;
+       u32 fail_frames;
+       u32 last_rates[IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES];
+       int last_frame_idx;
+};
+
 struct iwl_mvm {
        /* for logger access */
        struct device *dev;
@@ -519,6 +540,7 @@ struct iwl_mvm {
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        struct dentry *debugfs_dir;
        u32 dbgfs_sram_offset, dbgfs_sram_len;
+       u32 dbgfs_prph_reg_addr;
        bool disable_power_off;
        bool disable_power_off_d3;
 
@@ -526,6 +548,9 @@ struct iwl_mvm {
        struct debugfs_blob_wrapper nvm_sw_blob;
        struct debugfs_blob_wrapper nvm_calib_blob;
        struct debugfs_blob_wrapper nvm_prod_blob;
+
+       struct iwl_mvm_frame_stats drv_rx_stats;
+       spinlock_t drv_stats_lock;
 #endif
 
        struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
@@ -587,8 +612,6 @@ struct iwl_mvm {
        u8 first_agg_queue;
        u8 last_agg_queue;
 
-       u8 bound_vif_cnt;
-
        /* Indicate if device power save is allowed */
        bool ps_disabled;
        /* Indicate if device power management is allowed */
@@ -812,6 +835,10 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 
 /* rate scaling */
 int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
+void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
+                               struct iwl_mvm_frame_stats *stats,
+                               u32 rate, bool agg);
+int rs_pretty_print_rate(char *buf, const u32 rate);
 
 /* power management */
 int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm);
index 2d5251b3600c68a736d25cf0206481198d884747..cf2d09f53782b0227f9a47d9a8761af8b5ea7ffe 100644 (file)
@@ -228,13 +228,23 @@ static struct iwl_nvm_data *
 iwl_parse_nvm_sections(struct iwl_mvm *mvm)
 {
        struct iwl_nvm_section *sections = mvm->nvm_sections;
-       const __le16 *hw, *sw, *calib;
+       const __le16 *hw, *sw, *calib, *regulatory, *mac_override;
 
        /* Checking for required sections */
-       if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
-           !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
-               IWL_ERR(mvm, "Can't parse empty NVM sections\n");
-               return NULL;
+       if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+               if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
+                   !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
+                       IWL_ERR(mvm, "Can't parse empty NVM sections\n");
+                       return NULL;
+               }
+       } else {
+               if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
+                   !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data ||
+                   !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) {
+                       IWL_ERR(mvm,
+                               "Can't parse empty family 8000 NVM sections\n");
+                       return NULL;
+               }
        }
 
        if (WARN_ON(!mvm->cfg))
@@ -243,9 +253,14 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
        hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
        sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
        calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
+       regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data;
+       mac_override =
+               (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data;
+
        return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
-                                 iwl_fw_valid_tx_ant(mvm->fw),
-                                 iwl_fw_valid_rx_ant(mvm->fw));
+                                 regulatory, mac_override,
+                                 mvm->fw->valid_tx_ant,
+                                 mvm->fw->valid_rx_ant);
 }
 
 #define MAX_NVM_FILE_LEN       16384
@@ -285,6 +300,8 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
 
 #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
 #define NVM_WORD2_ID(x) (x >> 12)
+#define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8))
+#define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4)
 
        IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
 
@@ -335,8 +352,16 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
                        break;
                }
 
-               section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
-               section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
+               if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+                       section_size =
+                               2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
+                       section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
+               } else {
+                       section_size = 2 * NVM_WORD2_LEN_FAMILY_8000(
+                                               le16_to_cpu(file_sec->word2));
+                       section_id = NVM_WORD1_ID_FAMILY_8000(
+                                               le16_to_cpu(file_sec->word1));
+               }
 
                if (section_size > IWL_MAX_NVM_SECTION_SIZE) {
                        IWL_ERR(mvm, "ERROR - section too large (%d)\n",
@@ -406,6 +431,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
 {
        int ret, i, section;
        u8 *nvm_buffer, *temp;
+       int nvm_to_read[NVM_MAX_NUM_SECTIONS];
+       int num_of_sections_to_read;
 
        if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS))
                return -EINVAL;
@@ -418,12 +445,20 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
                        return ret;
        } else {
                /* list of NVM sections we are allowed/need to read */
-               int nvm_to_read[] = {
-                       mvm->cfg->nvm_hw_section_num,
-                       NVM_SECTION_TYPE_SW,
-                       NVM_SECTION_TYPE_CALIBRATION,
-                       NVM_SECTION_TYPE_PRODUCTION,
-               };
+               if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+                       nvm_to_read[0] = mvm->cfg->nvm_hw_section_num;
+                       nvm_to_read[1] = NVM_SECTION_TYPE_SW;
+                       nvm_to_read[2] = NVM_SECTION_TYPE_CALIBRATION;
+                       nvm_to_read[3] = NVM_SECTION_TYPE_PRODUCTION;
+                       num_of_sections_to_read = 4;
+               } else {
+                       nvm_to_read[0] = NVM_SECTION_TYPE_SW;
+                       nvm_to_read[1] = NVM_SECTION_TYPE_CALIBRATION;
+                       nvm_to_read[2] = NVM_SECTION_TYPE_PRODUCTION;
+                       nvm_to_read[3] = NVM_SECTION_TYPE_REGULATORY;
+                       nvm_to_read[4] = NVM_SECTION_TYPE_MAC_OVERRIDE;
+                       num_of_sections_to_read = 5;
+               }
 
                /* Read From FW NVM */
                IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
@@ -433,7 +468,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
                                     GFP_KERNEL);
                if (!nvm_buffer)
                        return -ENOMEM;
-               for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
+               for (i = 0; i < num_of_sections_to_read; i++) {
                        section = nvm_to_read[i];
                        /* we override the constness for initial read */
                        ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
index a46f0b8b0870aa6b506dd26a20161fcd540d0c67..ae347fb16a5d74d1b7e7b1409e65875e98efd47d 100644 (file)
@@ -245,7 +245,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
 #undef RX_HANDLER
 #define CMD(x) [x] = #x
 
-static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
+static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(MVM_ALIVE),
        CMD(REPLY_ERROR),
        CMD(INIT_COMPLETE_NOTIF),
index b7268c0b33339c975a93eca4450d145bfa27137b..237efe0ac1c44dab52d375ced3cb84912aabe082 100644 (file)
@@ -156,13 +156,13 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
        idle_cnt = chains_static;
        active_cnt = chains_dynamic;
 
-       cmd->rxchain_info = cpu_to_le32(iwl_fw_valid_rx_ant(mvm->fw) <<
+       cmd->rxchain_info = cpu_to_le32(mvm->fw->valid_rx_ant <<
                                        PHY_RX_CHAIN_VALID_POS);
        cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
        cmd->rxchain_info |= cpu_to_le32(active_cnt <<
                                         PHY_RX_CHAIN_MIMO_CNT_POS);
 
-       cmd->txchain_info = cpu_to_le32(iwl_fw_valid_tx_ant(mvm->fw));
+       cmd->txchain_info = cpu_to_le32(mvm->fw->valid_tx_ant);
 }
 
 /*
index 4da1ea44f39abc70fa82f0e68380fd9b0923c2ab..def6ec5173b9d8bbabe5e5e4e3a681b41af96f31 100644 (file)
@@ -425,7 +425,7 @@ static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
                return 0;
 
        if (vif->p2p &&
-           !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS))
+           !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))
                return 0;
 
        iwl_mvm_power_build_cmd(mvm, vif, &cmd);
@@ -511,8 +511,11 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
 struct iwl_power_constraint {
        struct ieee80211_vif *bf_vif;
        struct ieee80211_vif *bss_vif;
+       u16 bss_phyctx_id;
+       u16 p2p_phyctx_id;
        bool pm_disabled;
        bool ps_disabled;
+       struct iwl_mvm *mvm;
 };
 
 static void iwl_mvm_power_iterator(void *_data, u8 *mac,
@@ -520,6 +523,7 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac,
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_power_constraint *power_iterator = _data;
+       struct iwl_mvm *mvm = power_iterator->mvm;
 
        switch (ieee80211_vif_type_p2p(vif)) {
        case NL80211_IFTYPE_P2P_DEVICE:
@@ -539,11 +543,28 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac,
                break;
 
        case NL80211_IFTYPE_P2P_CLIENT:
-               /* no BSS power mgmt if we have a P2P client*/
-               power_iterator->pm_disabled = true;
+               if (mvmvif->phy_ctxt)
+                       power_iterator->p2p_phyctx_id = mvmvif->phy_ctxt->id;
+
+               IWL_DEBUG_POWER(mvm, "p2p: p2p_id=%d, bss_id=%d\n",
+                               power_iterator->p2p_phyctx_id,
+                               power_iterator->bss_phyctx_id);
+               if (!(mvm->fw->ucode_capa.flags &
+                     IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) {
+                       /* no BSS power mgmt if we have a P2P client*/
+                       power_iterator->pm_disabled = true;
+               } else if (power_iterator->p2p_phyctx_id < MAX_PHYS &&
+                          power_iterator->bss_phyctx_id < MAX_PHYS &&
+                          power_iterator->p2p_phyctx_id ==
+                          power_iterator->bss_phyctx_id) {
+                       power_iterator->pm_disabled = true;
+               }
                break;
 
        case NL80211_IFTYPE_STATION:
+               if (mvmvif->phy_ctxt)
+                       power_iterator->bss_phyctx_id = mvmvif->phy_ctxt->id;
+
                /* we should have only one BSS vif */
                WARN_ON(power_iterator->bss_vif);
                power_iterator->bss_vif = vif;
@@ -551,6 +572,17 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac,
                if (mvmvif->bf_data.bf_enabled &&
                    !WARN_ON(power_iterator->bf_vif))
                        power_iterator->bf_vif = vif;
+
+               IWL_DEBUG_POWER(mvm, "bss: p2p_id=%d, bss_id=%d\n",
+                               power_iterator->p2p_phyctx_id,
+                               power_iterator->bss_phyctx_id);
+               if (mvm->fw->ucode_capa.flags &
+                   IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM &&
+                       (power_iterator->p2p_phyctx_id < MAX_PHYS &&
+                        power_iterator->bss_phyctx_id < MAX_PHYS &&
+                        power_iterator->p2p_phyctx_id ==
+                        power_iterator->bss_phyctx_id))
+                       power_iterator->pm_disabled = true;
                break;
 
        default:
@@ -572,16 +604,16 @@ iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm,
        ieee80211_iterate_active_interfaces_atomic(mvm->hw,
                                            IEEE80211_IFACE_ITER_NORMAL,
                                            iwl_mvm_power_iterator, constraint);
-
-       /* TODO: remove this and determine this variable in the iterator */
-       if (mvm->bound_vif_cnt > 1)
-               constraint->pm_disabled = true;
 }
 
 int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_power_constraint constraint = {};
+       struct iwl_power_constraint constraint = {
+                   .p2p_phyctx_id = MAX_PHYS,
+                   .bss_phyctx_id = MAX_PHYS,
+                   .mvm = mvm,
+       };
        bool ba_enable;
        int ret;
 
index 32bb8075121cdb4eeaaab80ad926fabf5bc7b620..399709f2be2ecb20ff62db1f0725200d11ab54ba 100644 (file)
@@ -166,7 +166,7 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        if (sta->smps_mode == IEEE80211_SMPS_STATIC)
                return false;
 
-       if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2)
+       if (num_of_ant(mvm->fw->valid_tx_ant) < 2)
                return false;
 
        if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
@@ -917,7 +917,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
 
 
        if (num_of_ant(rate->ant) > 1)
-               rate->ant = first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
+               rate->ant = first_antenna(mvm->fw->valid_tx_ant);
 
        /* Relevant in both switching to SISO or Legacy */
        rate->sgi = false;
@@ -1477,7 +1477,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
        const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column];
        const struct rs_tx_column *next_col;
        allow_column_func_t allow_func;
-       u8 valid_ants = iwl_fw_valid_tx_ant(mvm->fw);
+       u8 valid_ants = mvm->fw->valid_tx_ant;
        const u16 *expected_tpt_tbl;
        s32 tpt, max_expected_tpt;
 
@@ -2089,7 +2089,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
 
        i = lq_sta->last_txrate_idx;
 
-       valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
+       valid_tx_ant = mvm->fw->valid_tx_ant;
 
        if (!lq_sta->search_better_tbl)
                active_tbl = lq_sta->active_tbl;
@@ -2240,6 +2240,73 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
        }
 }
 
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm,
+                                     struct iwl_mvm_frame_stats *stats)
+{
+       spin_lock_bh(&mvm->drv_stats_lock);
+       memset(stats, 0, sizeof(*stats));
+       spin_unlock_bh(&mvm->drv_stats_lock);
+}
+
+void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
+                               struct iwl_mvm_frame_stats *stats,
+                               u32 rate, bool agg)
+{
+       u8 nss = 0, mcs = 0;
+
+       spin_lock(&mvm->drv_stats_lock);
+
+       if (agg)
+               stats->agg_frames++;
+
+       stats->success_frames++;
+
+       switch (rate & RATE_MCS_CHAN_WIDTH_MSK) {
+       case RATE_MCS_CHAN_WIDTH_20:
+               stats->bw_20_frames++;
+               break;
+       case RATE_MCS_CHAN_WIDTH_40:
+               stats->bw_40_frames++;
+               break;
+       case RATE_MCS_CHAN_WIDTH_80:
+               stats->bw_80_frames++;
+               break;
+       default:
+               WARN_ONCE(1, "bad BW. rate 0x%x", rate);
+       }
+
+       if (rate & RATE_MCS_HT_MSK) {
+               stats->ht_frames++;
+               mcs = rate & RATE_HT_MCS_RATE_CODE_MSK;
+               nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1;
+       } else if (rate & RATE_MCS_VHT_MSK) {
+               stats->vht_frames++;
+               mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK;
+               nss = ((rate & RATE_VHT_MCS_NSS_MSK) >>
+                      RATE_VHT_MCS_NSS_POS) + 1;
+       } else {
+               stats->legacy_frames++;
+       }
+
+       if (nss == 1)
+               stats->siso_frames++;
+       else if (nss == 2)
+               stats->mimo2_frames++;
+
+       if (rate & RATE_MCS_SGI_MSK)
+               stats->sgi_frames++;
+       else
+               stats->ngi_frames++;
+
+       stats->last_rates[stats->last_frame_idx] = rate;
+       stats->last_frame_idx = (stats->last_frame_idx + 1) %
+               ARRAY_SIZE(stats->last_rates);
+
+       spin_unlock(&mvm->drv_stats_lock);
+}
+#endif
+
 /*
  * Called after adding a new station to initialize rate scaling
  */
@@ -2319,7 +2386,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 
        /* These values will be overridden later */
        lq_sta->lq.single_stream_ant_msk =
-               first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
+               first_antenna(mvm->fw->valid_tx_ant);
        lq_sta->lq.dual_stream_ant_msk = ANT_AB;
 
        /* as default allow aggregation for all tids */
@@ -2334,7 +2401,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 #ifdef CONFIG_MAC80211_DEBUGFS
        lq_sta->dbg_fixed_rate = 0;
 #endif
-
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats);
+#endif
        rs_initialize_lq(mvm, sta, lq_sta, band, init);
 }
 
@@ -2445,7 +2514,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
 
        memcpy(&rate, initial_rate, sizeof(rate));
 
-       valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
+       valid_tx_ant = mvm->fw->valid_tx_ant;
 
        if (is_siso(&rate)) {
                num_rates = RS_INITIAL_SISO_NUM_RATES;
@@ -2546,7 +2615,7 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta,
 }
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-static int rs_pretty_print_rate(char *buf, const u32 rate)
+int rs_pretty_print_rate(char *buf, const u32 rate)
 {
 
        char *type, *bw;
@@ -2595,7 +2664,7 @@ static int rs_pretty_print_rate(char *buf, const u32 rate)
        return sprintf(buf, "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s\n",
                       type, rs_pretty_ant(ant), bw, mcs, nss,
                       (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ",
-                      (rate & RATE_MCS_STBC_MSK) ? "STBC " : "",
+                      (rate & RATE_MCS_HT_STBC_MSK) ? "STBC " : "",
                       (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "",
                       (rate & RATE_MCS_BF_MSK) ? "BF " : "",
                       (rate & RATE_MCS_ZLF_MSK) ? "ZLF " : "");
@@ -2676,9 +2745,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
        desc += sprintf(buff+desc, "fixed rate 0x%X\n",
                        lq_sta->dbg_fixed_rate);
        desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
-           (iwl_fw_valid_tx_ant(mvm->fw) & ANT_A) ? "ANT_A," : "",
-           (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "",
-           (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : "");
+           (mvm->fw->valid_tx_ant & ANT_A) ? "ANT_A," : "",
+           (mvm->fw->valid_tx_ant & ANT_B) ? "ANT_B," : "",
+           (mvm->fw->valid_tx_ant & ANT_C) ? "ANT_C" : "");
        desc += sprintf(buff+desc, "lq type %s\n",
                        (is_legacy(rate)) ? "legacy" :
                        is_vht(rate) ? "VHT" : "HT");
index fa3c1393e1032e05170389ae61e65c107fa129a2..6061553a5e444956c7b5d626695a2950fb1f3fd1 100644 (file)
@@ -77,6 +77,15 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 
        memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info));
        mvm->ampdu_ref++;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
+               spin_lock(&mvm->drv_stats_lock);
+               mvm->drv_rx_stats.ampdu_count++;
+               spin_unlock(&mvm->drv_stats_lock);
+       }
+#endif
+
        return 0;
 }
 
@@ -368,21 +377,33 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                rx_status.flag |= RX_FLAG_SHORT_GI;
        if (rate_n_flags & RATE_HT_MCS_GF_MSK)
                rx_status.flag |= RX_FLAG_HT_GF;
+       if (rate_n_flags & RATE_MCS_LDPC_MSK)
+               rx_status.flag |= RX_FLAG_LDPC;
        if (rate_n_flags & RATE_MCS_HT_MSK) {
+               u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >>
+                               RATE_MCS_STBC_POS;
                rx_status.flag |= RX_FLAG_HT;
                rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+               rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT;
        } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+               u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >>
+                               RATE_MCS_STBC_POS;
                rx_status.vht_nss =
                        ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
                                                RATE_VHT_MCS_NSS_POS) + 1;
                rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
                rx_status.flag |= RX_FLAG_VHT;
+               rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT;
        } else {
                rx_status.rate_idx =
                        iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
                                                            rx_status.band);
        }
 
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags,
+                                  rx_status.flag & RX_FLAG_AMPDU_DETAILS);
+#endif
        iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status,
                                        rxb, &rx_status);
        return 0;
index eba55cc3352db3cb2997f39e8586b48ed63762ec..713efd71efe26b6eb4f545c4a7f306813f77c1dc 100644 (file)
@@ -82,7 +82,7 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
        if (mvm->scan_rx_ant != ANT_NONE)
                rx_ant = mvm->scan_rx_ant;
        else
-               rx_ant = iwl_fw_valid_rx_ant(mvm->fw);
+               rx_ant = mvm->fw->valid_rx_ant;
        rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS;
        rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
        rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS;
@@ -124,7 +124,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
        u32 tx_ant;
 
        mvm->scan_last_antenna_idx =
-               iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
+               iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
                                     mvm->scan_last_antenna_idx);
        tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS;
 
index e145dd41e85ec7d7e95ecf05257aac7a4dee8875..61331245ad9324f29ec5a86f12a3239725619673 100644 (file)
@@ -438,7 +438,8 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
        time_cmd.duration = cpu_to_le32(duration);
        time_cmd.repeat = 1;
        time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
-                                     TE_V2_NOTIF_HOST_EVENT_END);
+                                     TE_V2_NOTIF_HOST_EVENT_END |
+                                     T2_V2_START_IMMEDIATELY);
 
        iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
 }
@@ -553,7 +554,8 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
        time_cmd.repeat = 1;
        time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
-                                     TE_V2_NOTIF_HOST_EVENT_END);
+                                     TE_V2_NOTIF_HOST_EVENT_END |
+                                     T2_V2_START_IMMEDIATELY);
 
        return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
 }
index 74d60bf27750ae7d88dda39fbf473f971ddd8f79..0ba96654d2c3516e5528639708cf9c53d0cc639f 100644 (file)
@@ -122,7 +122,7 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
                 * it
                 */
                WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU);
-       } else if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
+       } else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) {
                tx_cmd->pm_frame_timeout = cpu_to_le16(2);
        } else {
                tx_cmd->pm_frame_timeout = 0;
@@ -207,7 +207,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
        rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx);
 
        mvm->mgmt_last_antenna_idx =
-               iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
+               iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
                                     mvm->mgmt_last_antenna_idx);
        rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
 
@@ -845,16 +845,12 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data;
        struct sk_buff_head reclaimed_skbs;
        struct iwl_mvm_tid_data *tid_data;
-       struct ieee80211_tx_info *info;
        struct ieee80211_sta *sta;
        struct iwl_mvm_sta *mvmsta;
-       struct ieee80211_hdr *hdr;
        struct sk_buff *skb;
        int sta_id, tid, freed;
-
        /* "flow" corresponds to Tx queue */
        u16 scd_flow = le16_to_cpu(ba_notif->scd_flow);
-
        /* "ssn" is start of block-ack Tx window, corresponds to index
         * (in Tx queue's circular buffer) of first TFD/frame in window */
        u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn);
@@ -911,22 +907,26 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        freed = 0;
 
        skb_queue_walk(&reclaimed_skbs, skb) {
-               hdr = (struct ieee80211_hdr *)skb->data;
+               struct ieee80211_hdr *hdr = (void *)skb->data;
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
                if (ieee80211_is_data_qos(hdr->frame_control))
                        freed++;
                else
                        WARN_ON_ONCE(1);
 
-               info = IEEE80211_SKB_CB(skb);
                iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
 
+               memset(&info->status, 0, sizeof(info->status));
+               /* Packet was transmitted successfully, failures come as single
+                * frames because before failing a frame the firmware transmits
+                * it without aggregation at least once.
+                */
+               info->flags |= IEEE80211_TX_STAT_ACK;
+
                if (freed == 1) {
                        /* this is the first skb we deliver in this batch */
                        /* put the rate scaling data there */
-                       info = IEEE80211_SKB_CB(skb);
-                       memset(&info->status, 0, sizeof(info->status));
-                       info->flags |= IEEE80211_TX_STAT_ACK;
                        info->flags |= IEEE80211_TX_STAT_AMPDU;
                        info->status.ampdu_ack_len = ba_notif->txed_2_done;
                        info->status.ampdu_len = ba_notif->txed;
index 1493f79e67e0fb0b00b490a800094c5859cdbffa..bbfe529d7b64e8d5b3789fd7cc4b53adcc882d0f 100644 (file)
@@ -289,8 +289,8 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx)
        return last_idx;
 }
 
-static struct {
-       char *name;
+static const struct {
+       const char *name;
        u8 num;
 } advanced_lookup[] = {
        { "NMI_INTERRUPT_WDG", 0x34 },
@@ -589,7 +589,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        lockdep_assert_held(&mvm->mutex);
 
        /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */
-       if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1)
+       if (num_of_ant(mvm->fw->valid_rx_ant) == 1)
                return;
 
        if (vif->type == NL80211_IFTYPE_AP)
index 0f52e961a5a514f069e80b139a3e5df484b5e76e..1f97631a82e423b1c0a09f709adbfe6ab6225d43 100644 (file)
@@ -360,13 +360,12 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
 /* 7265 Series */
        {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5110, iwl7265_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x095A, 0x5112, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5100, iwl7265_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x095A, 0x510A, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)},
        {IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x5412, 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)},
index e851f26fd44c1644c81b24f9a91b690ab2fb418e..3120bc5bb12d76331f387c23a2bb479384ed818f 100644 (file)
@@ -304,7 +304,7 @@ struct iwl_trans_pcie {
        bool bc_table_dword;
        u32 rx_page_order;
 
-       const char **command_names;
+       const char *const *command_names;
 
        /* queue watchdog */
        unsigned long wd_timeout;
index 41f684deff973a628a73304f7ef083ae24361f45..cf49f6ce0ff813ec9d4ab5a0d36cba582bea22ba 100644 (file)
@@ -155,37 +155,26 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
        if (rxq->need_update == 0)
                goto exit_unlock;
 
-       if (trans->cfg->base_params->shadow_reg_enable) {
-               /* shadow register enabled */
-               /* Device expects a multiple of 8 */
-               rxq->write_actual = (rxq->write & ~0x7);
-               iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
-       } else {
-               /* If power-saving is in use, make sure device is awake */
-               if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
-                       reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
-
-                       if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-                               IWL_DEBUG_INFO(trans,
-                                       "Rx queue requesting wakeup,"
-                                       " GP1 = 0x%x\n", reg);
-                               iwl_set_bit(trans, CSR_GP_CNTRL,
-                                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-                               goto exit_unlock;
-                       }
-
-                       rxq->write_actual = (rxq->write & ~0x7);
-                       iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
-                                          rxq->write_actual);
-
-               /* Else device is assumed to be awake */
-               } else {
-                       /* Device expects a multiple of 8 */
-                       rxq->write_actual = (rxq->write & ~0x7);
-                       iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
-                                          rxq->write_actual);
+       /*
+        * explicitly wake up the NIC if:
+        * 1. shadow registers aren't enabled
+        * 2. there is a chance that the NIC is asleep
+        */
+       if (!trans->cfg->base_params->shadow_reg_enable &&
+           test_bit(STATUS_TPOWER_PMI, &trans->status)) {
+               reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
+
+               if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+                       IWL_DEBUG_INFO(trans, "Rx queue requesting wakeup, GP1 = 0x%x\n",
+                                      reg);
+                       iwl_set_bit(trans, CSR_GP_CNTRL,
+                                   CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+                       goto exit_unlock;
                }
        }
+
+       rxq->write_actual = round_down(rxq->write, 8);
+       iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
        rxq->need_update = 0;
 
  exit_unlock:
index 254126447c683619c000fea3e52be0b6039d9302..3b0c72c1005446d2d93f7eb15ed6d3207e1c3ea1 100644 (file)
@@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
                IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
                        le32_to_cpu(txq->scratchbufs[i].scratch));
 
-       iwl_trans_fw_error(trans);
+       iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1);
 }
 
 /*
@@ -296,43 +296,38 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
        if (txq->need_update == 0)
                return;
 
-       if (trans->cfg->base_params->shadow_reg_enable ||
-           txq_id == trans_pcie->cmd_queue) {
-               /* shadow register enabled */
-               iwl_write32(trans, HBUS_TARG_WRPTR,
-                           txq->q.write_ptr | (txq_id << 8));
-       } else {
-               /* if we're trying to save power */
-               if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
-                       /* wake up nic if it's powered down ...
-                        * uCode will wake up, and interrupt us again, so next
-                        * time we'll skip this part. */
-                       reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
-
-                       if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-                               IWL_DEBUG_INFO(trans,
-                                       "Tx queue %d requesting wakeup,"
-                                       " GP1 = 0x%x\n", txq_id, reg);
-                               iwl_set_bit(trans, CSR_GP_CNTRL,
-                                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-                               return;
-                       }
-
-                       IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id,
-                                    txq->q.write_ptr);
-
-                       iwl_write_direct32(trans, HBUS_TARG_WRPTR,
-                                    txq->q.write_ptr | (txq_id << 8));
-
+       /*
+        * explicitly wake up the NIC if:
+        * 1. shadow registers aren't enabled
+        * 2. NIC is woken up for CMD regardless of shadow outside this function
+        * 3. there is a chance that the NIC is asleep
+        */
+       if (!trans->cfg->base_params->shadow_reg_enable &&
+           txq_id != trans_pcie->cmd_queue &&
+           test_bit(STATUS_TPOWER_PMI, &trans->status)) {
                /*
-                * else not in power-save mode,
-                * uCode will never sleep when we're
-                * trying to tx (during RFKILL, we're not trying to tx).
+                * wake up nic if it's powered down ...
+                * uCode will wake up, and interrupt us again, so next
+                * time we'll skip this part.
                 */
-               } else
-                       iwl_write32(trans, HBUS_TARG_WRPTR,
-                                   txq->q.write_ptr | (txq_id << 8));
+               reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
+
+               if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+                       IWL_DEBUG_INFO(trans, "Tx queue %d requesting wakeup, GP1 = 0x%x\n",
+                                      txq_id, reg);
+                       iwl_set_bit(trans, CSR_GP_CNTRL,
+                                   CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+                       return;
+               }
        }
+
+       /*
+        * if not in power-save mode, uCode will never sleep when we're
+        * trying to tx (during RFKILL, we're not trying to tx).
+        */
+       IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->q.write_ptr);
+       iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8));
+
        txq->need_update = 0;
 }
 
@@ -1029,7 +1024,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
                if (nfreed++ > 0) {
                        IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
                                idx, q->write_ptr, q->read_ptr);
-                       iwl_trans_fw_error(trans);
+                       iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1);
                }
        }
 
@@ -1588,6 +1583,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
                               get_cmd_string(trans_pcie, cmd->id));
                ret = -ETIMEDOUT;
 
+               iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1);
                iwl_trans_fw_error(trans);
 
                goto cancel;
index 2d72a6b4b93e927b37c0e7ee2c5d316c475b3a47..54e344aed6e05d097c3eb60462d74064757b81fc 100644 (file)
@@ -621,7 +621,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                        id = *pos++;
                        elen = *pos++;
                        left -= 2;
-                       if (elen > left || elen == 0) {
+                       if (elen > left) {
                                lbs_deb_scan("scan response: invalid IE fmt\n");
                                goto done;
                        }
index 58c6ee5de98f9256b2e3db4735adbfe1fed299bd..33ceda296c9c61ece7d14a8484cd551b50026dfa 100644 (file)
@@ -498,7 +498,7 @@ static int if_sdio_prog_helper(struct if_sdio_card *card,
                 */
                mdelay(2);
 
-               chunk_size = min(size, (size_t)60);
+               chunk_size = min_t(size_t, size, 60);
 
                *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
                memcpy(chunk_buffer + 4, firmware, chunk_size);
@@ -639,7 +639,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card,
                        req_size = size;
 
                while (req_size) {
-                       chunk_size = min(req_size, (size_t)512);
+                       chunk_size = min_t(size_t, req_size, 512);
 
                        memcpy(chunk_buffer, firmware, chunk_size);
 /*
index f7e3562542feae86fdf4ad62cc06a86aac47f67b..9d7a52f5a4102abedd2dbebc03c26c3866da2a64 100644 (file)
@@ -411,6 +411,7 @@ struct mac80211_hwsim_data {
 
        struct mac_address addresses[2];
        int channels, idx;
+       bool use_chanctx;
 
        struct ieee80211_channel *tmp_chan;
        struct delayed_work roc_done;
@@ -1088,7 +1089,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
                return;
        }
 
-       if (data->channels == 1) {
+       if (!data->use_chanctx) {
                channel = data->channel;
        } else if (txi->hw_queue == 4) {
                channel = data->tmp_chan;
@@ -1354,7 +1355,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 
        data->channel = conf->chandef.chan;
 
-       WARN_ON(data->channel && data->channels > 1);
+       WARN_ON(data->channel && data->use_chanctx);
 
        data->power_level = conf->power_level;
        if (!data->started || !data->beacon_int)
@@ -1940,7 +1941,8 @@ static struct ieee80211_ops mac80211_hwsim_mchan_ops;
 
 static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                                       const struct ieee80211_regdomain *regd,
-                                      bool reg_strict, bool p2p_device)
+                                      bool reg_strict, bool p2p_device,
+                                      bool use_chanctx)
 {
        int err;
        u8 addr[ETH_ALEN];
@@ -1950,11 +1952,14 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
        int idx;
 
+       if (WARN_ON(channels > 1 && !use_chanctx))
+               return -EINVAL;
+
        spin_lock_bh(&hwsim_radio_lock);
        idx = hwsim_radio_idx++;
        spin_unlock_bh(&hwsim_radio_lock);
 
-       if (channels > 1)
+       if (use_chanctx)
                ops = &mac80211_hwsim_mchan_ops;
        hw = ieee80211_alloc_hw(sizeof(*data), ops);
        if (!hw) {
@@ -1995,20 +2000,21 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        hw->wiphy->addresses = data->addresses;
 
        data->channels = channels;
+       data->use_chanctx = use_chanctx;
        data->idx = idx;
 
-       if (data->channels > 1) {
+       if (data->use_chanctx) {
                hw->wiphy->max_scan_ssids = 255;
                hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
                hw->wiphy->max_remain_on_channel_duration = 1000;
                /* For channels > 1 DFS is not allowed */
                hw->wiphy->n_iface_combinations = 1;
                hw->wiphy->iface_combinations = &data->if_combination;
-               data->if_combination.num_different_channels = data->channels;
                if (p2p_device)
                        data->if_combination = hwsim_if_comb_p2p_dev[0];
                else
                        data->if_combination = hwsim_if_comb[0];
+               data->if_combination.num_different_channels = data->channels;
        } else if (p2p_device) {
                hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
                hw->wiphy->n_iface_combinations =
@@ -2156,7 +2162,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
        debugfs_create_file("group", 0666, data->debugfs, data,
                            &hwsim_fops_group);
-       if (data->channels == 1)
+       if (!data->use_chanctx)
                debugfs_create_file("dfs_simulate_radar", 0222,
                                    data->debugfs,
                                    data, &hwsim_simulate_radar);
@@ -2423,10 +2429,16 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
        const struct ieee80211_regdomain *regd = NULL;
        bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
        bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
+       bool use_chanctx;
 
        if (info->attrs[HWSIM_ATTR_CHANNELS])
                chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
 
+       if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
+               use_chanctx = true;
+       else
+               use_chanctx = (chans > 1);
+
        if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
                alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
 
@@ -2439,7 +2451,7 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
        }
 
        return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
-                                          p2p_device);
+                                          p2p_device, use_chanctx);
 }
 
 static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
@@ -2658,7 +2670,8 @@ static int __init init_mac80211_hwsim(void)
 
                err = mac80211_hwsim_create_radio(channels, reg_alpha2,
                                                  regd, reg_strict,
-                                                 support_p2p_device);
+                                                 support_p2p_device,
+                                                 channels > 1);
                if (err < 0)
                        goto out_free_radios;
        }
index 6e72996ec8c1f1dae6386a5e9755fa6b3a5041ba..c9d0315575bab27035378378d396a46db828bf4c 100644 (file)
@@ -108,6 +108,9 @@ enum {
  * @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute)
  * @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute)
  * @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag)
+ * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO
+ *     command to force use of channel contexts even when only a
+ *     single channel is supported
  * @__HWSIM_ATTR_MAX: enum limit
  */
 
@@ -128,6 +131,7 @@ enum {
        HWSIM_ATTR_REG_CUSTOM_REG,
        HWSIM_ATTR_REG_STRICT_REG,
        HWSIM_ATTR_SUPPORT_P2P_DEVICE,
+       HWSIM_ATTR_USE_CHANCTX,
        __HWSIM_ATTR_MAX,
 };
 #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
index bb43251c18f2bb0bc7a87404372d7aed9d277113..c92f27aa71ede1f049c101a0ba185f31d982aaa3 100644 (file)
@@ -192,8 +192,7 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
                vht_cap->header.len  =
                                cpu_to_le16(sizeof(struct ieee80211_vht_cap));
                memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header),
-                      (u8 *)bss_desc->bcn_vht_cap +
-                      sizeof(struct ieee_types_header),
+                      (u8 *)bss_desc->bcn_vht_cap,
                       le16_to_cpu(vht_cap->header.len));
 
                mwifiex_fill_vht_cap_tlv(priv, &vht_cap->vht_cap,
index 8d683070bdb30df702bd1384281e17f639e755da..e76b0db4e3e6392236489affbfcba48b98468348 100644 (file)
@@ -73,8 +73,8 @@ static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
 {
        u32 enable = flag;
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
-                                    HostCmd_ACT_GEN_SET, DOT11H_I, &enable);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                               HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true);
 }
 
 /* This functions processes TLV buffer for a pending BSS Join command.
index 37677af8d2fc308a77944ed52232382b4356638a..d9c65b60cd7281f26d3f332ab74b6ffa58c38a88 100644 (file)
@@ -317,8 +317,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
                ht_cap->header.len =
                                cpu_to_le16(sizeof(struct ieee80211_ht_cap));
                memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
-                      (u8 *) bss_desc->bcn_ht_cap +
-                      sizeof(struct ieee_types_header),
+                      (u8 *)bss_desc->bcn_ht_cap,
                       le16_to_cpu(ht_cap->header.len));
 
                mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap);
@@ -574,8 +573,8 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
        memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
 
        /* We don't wait for the response of this command */
-       ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ,
-                                    0, 0, &add_ba_req);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
+                              0, 0, &add_ba_req, false);
 
        return ret;
 }
@@ -602,8 +601,8 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
        memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
 
        /* We don't wait for the response of this command */
-       ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA,
-                                    HostCmd_ACT_GEN_SET, 0, &delba);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA,
+                              HostCmd_ACT_GEN_SET, 0, &delba, false);
 
        return ret;
 }
index b361257fb65e7d358bf53ae25b7a8401c41dead6..c3323c492614e97ad06f642a1bba25919b3bd416 100644 (file)
@@ -142,7 +142,7 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
        mwifiex_11n_dispatch_pkt(priv, tbl, (tbl->start_win + tbl->win_size) &
                                            (MAX_TID_VALUE - 1));
 
-       del_timer(&tbl->timer_context.timer);
+       del_timer_sync(&tbl->timer_context.timer);
 
        spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
        list_del(&tbl->list);
@@ -279,6 +279,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
        new_node->tid = tid;
        memcpy(new_node->ta, ta, ETH_ALEN);
        new_node->start_win = seq_num;
+       new_node->init_win = seq_num;
+       new_node->flags = 0;
 
        if (mwifiex_queuing_ra_based(priv)) {
                dev_dbg(priv->adapter->dev,
@@ -298,11 +300,12 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
        }
 
        if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
-           last_seq >= new_node->start_win)
+           last_seq >= new_node->start_win) {
                new_node->start_win = last_seq + 1;
+               new_node->flags |= RXREOR_INIT_WINDOW_SHIFT;
+       }
 
        new_node->win_size = win_size;
-       new_node->flags = 0;
 
        new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
                                        GFP_KERNEL);
@@ -452,6 +455,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
        struct mwifiex_rx_reorder_tbl *tbl;
        int start_win, end_win, win_size;
        u16 pkt_index;
+       bool init_window_shift = false;
 
        tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
        if (!tbl) {
@@ -466,19 +470,29 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
        start_win = tbl->start_win;
        win_size = tbl->win_size;
        end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
-       del_timer(&tbl->timer_context.timer);
+       if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) {
+               init_window_shift = true;
+               tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT;
+       }
        mod_timer(&tbl->timer_context.timer,
                  jiffies + msecs_to_jiffies(MIN_FLUSH_TIMER_MS * win_size));
 
-       /*
-        * If seq_num is less then starting win then ignore and drop the
-        * packet
-        */
        if (tbl->flags & RXREOR_FORCE_NO_DROP) {
                dev_dbg(priv->adapter->dev,
                        "RXREOR_FORCE_NO_DROP when HS is activated\n");
                tbl->flags &= ~RXREOR_FORCE_NO_DROP;
+       } else if (init_window_shift && seq_num < start_win &&
+                  seq_num >= tbl->init_win) {
+               dev_dbg(priv->adapter->dev,
+                       "Sender TID sequence number reset %d->%d for SSN %d\n",
+                       start_win, seq_num, tbl->init_win);
+               tbl->start_win = start_win = seq_num;
+               end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
        } else {
+               /*
+                * If seq_num is less then starting win then ignore and drop
+                * the packet
+                */
                if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
                        if (seq_num >= ((start_win + TWOPOW11) &
                                        (MAX_TID_VALUE - 1)) &&
@@ -636,7 +650,7 @@ void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
        delba.del_ba_param_set |= cpu_to_le16(
                (u16) event->origninator << DELBA_INITIATOR_POS);
        delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
-       mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba);
+       mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba, false);
 }
 
 /*
index 4064041ac852737602b8970eff8c40f4070c9117..0fc76e4a60f886c32d3e46cf885cbcc809ee9893 100644 (file)
@@ -42,7 +42,8 @@
 #define BA_SETUP_PACKET_OFFSET         16
 
 enum mwifiex_rxreor_flags {
-       RXREOR_FORCE_NO_DROP    = 1<<0,
+       RXREOR_FORCE_NO_DROP            = 1<<0,
+       RXREOR_INIT_WINDOW_SHIFT        = 1<<1,
 };
 
 static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
index 3d64613ebb2979426d9fd1652b9fc17325cf8676..b9242c3dca435ee9a4d5123fd57ad0733a96a24d 100644 (file)
@@ -131,7 +131,7 @@ info
        hs_configured = <0/1, host sleep not configured/configured>
        hs_activated = <0/1, extended host sleep not activated/activated>
        num_tx_timeout = <number of Tx timeout>
-       num_cmd_timeout = <number of timeout commands>
+       is_cmd_timedout = <0/1 command timeout not occurred/occurred>
        timeout_cmd_id = <command id of the last timeout command>
        timeout_cmd_act = <command action of the last timeout command>
        last_cmd_id = <command id of the last several commands sent to device>
index 436ba437a4ba198f2c469cad6545818e46cba730..51ce99cfcfb97f633028ceb045fb5b3b17d4494a 100644 (file)
@@ -252,9 +252,9 @@ mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
 
        if (mask != priv->mgmt_frame_mask) {
                priv->mgmt_frame_mask = mask;
-               mwifiex_send_cmd_async(priv, HostCmd_CMD_MGMT_FRAME_REG,
-                                      HostCmd_ACT_GEN_SET, 0,
-                                      &priv->mgmt_frame_mask);
+               mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG,
+                                HostCmd_ACT_GEN_SET, 0,
+                                &priv->mgmt_frame_mask, false);
                wiphy_dbg(wiphy, "info: mgmt frame registered\n");
        }
 }
@@ -515,8 +515,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
 
        priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
 
-       if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
-                                  HostCmd_ACT_GEN_SET, 0, NULL)) {
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+                            HostCmd_ACT_GEN_SET, 0, NULL, false)) {
                wiphy_err(wiphy, "11D: setting domain info in FW\n");
                return -1;
        }
@@ -580,9 +580,9 @@ mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
            frag_thr > MWIFIEX_FRAG_MAX_VALUE)
                frag_thr = MWIFIEX_FRAG_MAX_VALUE;
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
-                                    HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
-                                    &frag_thr);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                               HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
+                               &frag_thr, true);
 }
 
 /*
@@ -597,9 +597,9 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
        if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE)
                rts_thr = MWIFIEX_RTS_MAX_VALUE;
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
-                                   HostCmd_ACT_GEN_SET, RTS_THRESH_I,
-                                   &rts_thr);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                               HostCmd_ACT_GEN_SET, RTS_THRESH_I,
+                               &rts_thr, true);
 }
 
 /*
@@ -637,20 +637,19 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 
                        bss_started = priv->bss_started;
 
-                       ret = mwifiex_send_cmd_sync(priv,
-                                                   HostCmd_CMD_UAP_BSS_STOP,
-                                                   HostCmd_ACT_GEN_SET, 0,
-                                                   NULL);
+                       ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+                                              HostCmd_ACT_GEN_SET, 0,
+                                              NULL, true);
                        if (ret) {
                                wiphy_err(wiphy, "Failed to stop the BSS\n");
                                kfree(bss_cfg);
                                return ret;
                        }
 
-                       ret = mwifiex_send_cmd_async(priv,
-                                                    HostCmd_CMD_UAP_SYS_CONFIG,
-                                                    HostCmd_ACT_GEN_SET,
-                                                    UAP_BSS_PARAMS_I, bss_cfg);
+                       ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+                                              HostCmd_ACT_GEN_SET,
+                                              UAP_BSS_PARAMS_I, bss_cfg,
+                                              false);
 
                        kfree(bss_cfg);
 
@@ -662,10 +661,9 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
                        if (!bss_started)
                                break;
 
-                       ret = mwifiex_send_cmd_async(priv,
-                                                    HostCmd_CMD_UAP_BSS_START,
-                                                    HostCmd_ACT_GEN_SET, 0,
-                                                    NULL);
+                       ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
+                                              HostCmd_ACT_GEN_SET, 0,
+                                              NULL, false);
                        if (ret) {
                                wiphy_err(wiphy, "Failed to start BSS\n");
                                return ret;
@@ -700,8 +698,8 @@ mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv)
        if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA)
                mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA);
 
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
-                                 HostCmd_ACT_GEN_SET, 0, &mode))
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+                            HostCmd_ACT_GEN_SET, 0, &mode, true))
                return -1;
 
        return 0;
@@ -721,13 +719,13 @@ mwifiex_cfg80211_init_p2p_client(struct mwifiex_private *priv)
                return -1;
 
        mode = P2P_MODE_DEVICE;
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
-                                 HostCmd_ACT_GEN_SET, 0, &mode))
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+                            HostCmd_ACT_GEN_SET, 0, &mode, true))
                return -1;
 
        mode = P2P_MODE_CLIENT;
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
-                                 HostCmd_ACT_GEN_SET, 0, &mode))
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+                            HostCmd_ACT_GEN_SET, 0, &mode, true))
                return -1;
 
        return 0;
@@ -747,13 +745,13 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv)
                return -1;
 
        mode = P2P_MODE_DEVICE;
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
-                                 HostCmd_ACT_GEN_SET, 0, &mode))
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+                            HostCmd_ACT_GEN_SET, 0, &mode, true))
                return -1;
 
        mode = P2P_MODE_GO;
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
-                                 HostCmd_ACT_GEN_SET, 0, &mode))
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
+                            HostCmd_ACT_GEN_SET, 0, &mode, true))
                return -1;
 
        if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
@@ -853,8 +851,8 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
 
        priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
 
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE,
-                                   HostCmd_ACT_GEN_SET, 0, NULL);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+                              HostCmd_ACT_GEN_SET, 0, NULL, true);
 
        return ret;
 }
@@ -942,8 +940,8 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
                        STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
 
        /* Get signal information from the firmware */
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO,
-                                 HostCmd_ACT_GEN_GET, 0, NULL)) {
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
+                            HostCmd_ACT_GEN_GET, 0, NULL, true)) {
                dev_err(priv->adapter->dev, "failed to get signal information\n");
                return -EFAULT;
        }
@@ -954,9 +952,9 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
        }
 
        /* Get DTIM period information from firmware */
-       mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
-                             HostCmd_ACT_GEN_GET, DTIM_PERIOD_I,
-                             &priv->dtim_period);
+       mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                        HostCmd_ACT_GEN_GET, DTIM_PERIOD_I,
+                        &priv->dtim_period, true);
 
        mwifiex_parse_htinfo(priv, priv->tx_htinfo, &sinfo->txrate);
 
@@ -1186,8 +1184,8 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
        if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2)
                bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8;
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
-                                    HostCmd_ACT_GEN_SET, 0, bitmap_rates);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
+                               HostCmd_ACT_GEN_SET, 0, bitmap_rates, true);
 }
 
 /*
@@ -1216,14 +1214,14 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
                subsc_evt.bcn_h_rssi_cfg.abs_value = abs(rssi_thold);
                subsc_evt.bcn_l_rssi_cfg.evt_freq = 1;
                subsc_evt.bcn_h_rssi_cfg.evt_freq = 1;
-               return mwifiex_send_cmd_sync(priv,
-                                            HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
-                                            0, 0, &subsc_evt);
+               return mwifiex_send_cmd(priv,
+                                       HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+                                       0, 0, &subsc_evt, true);
        } else {
                subsc_evt.action = HostCmd_ACT_BITWISE_CLR;
-               return mwifiex_send_cmd_sync(priv,
-                                            HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
-                                            0, 0, &subsc_evt);
+               return mwifiex_send_cmd(priv,
+                                       HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+                                       0, 0, &subsc_evt, true);
        }
 
        return 0;
@@ -1276,10 +1274,9 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
        if (!mac || is_broadcast_ether_addr(mac)) {
                wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__);
                list_for_each_entry(sta_node, &priv->sta_list, list) {
-                       if (mwifiex_send_cmd_sync(priv,
-                                                 HostCmd_CMD_UAP_STA_DEAUTH,
-                                                 HostCmd_ACT_GEN_SET, 0,
-                                                 sta_node->mac_addr))
+                       if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
+                                            HostCmd_ACT_GEN_SET, 0,
+                                            sta_node->mac_addr, true))
                                return -1;
                        mwifiex_uap_del_sta_data(priv, sta_node);
                }
@@ -1289,10 +1286,9 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
                sta_node = mwifiex_get_sta_entry(priv, mac);
                spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
                if (sta_node) {
-                       if (mwifiex_send_cmd_sync(priv,
-                                                 HostCmd_CMD_UAP_STA_DEAUTH,
-                                                 HostCmd_ACT_GEN_SET, 0,
-                                                 sta_node->mac_addr))
+                       if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
+                                            HostCmd_ACT_GEN_SET, 0,
+                                            sta_node->mac_addr, true))
                                return -1;
                        mwifiex_uap_del_sta_data(priv, sta_node);
                }
@@ -1328,13 +1324,40 @@ mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
                        tx_ant = RF_ANTENNA_AUTO;
                        rx_ant = RF_ANTENNA_AUTO;
                }
+       } else {
+               struct ieee80211_sta_ht_cap *ht_info;
+               int rx_mcs_supp;
+               enum ieee80211_band band;
+
+               if ((tx_ant == 0x1 && rx_ant == 0x1)) {
+                       adapter->user_dev_mcs_support = HT_STREAM_1X1;
+                       if (adapter->is_hw_11ac_capable)
+                               adapter->usr_dot_11ac_mcs_support =
+                                               MWIFIEX_11AC_MCS_MAP_1X1;
+               } else {
+                       adapter->user_dev_mcs_support = HT_STREAM_2X2;
+                       if (adapter->is_hw_11ac_capable)
+                               adapter->usr_dot_11ac_mcs_support =
+                                               MWIFIEX_11AC_MCS_MAP_2X2;
+               }
+
+               for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+                       if (!adapter->wiphy->bands[band])
+                               continue;
+
+                       ht_info = &adapter->wiphy->bands[band]->ht_cap;
+                       rx_mcs_supp =
+                               GET_RXMCSSUPP(adapter->user_dev_mcs_support);
+                       memset(&ht_info->mcs, 0, adapter->number_of_antenna);
+                       memset(&ht_info->mcs, 0xff, rx_mcs_supp);
+               }
        }
 
        ant_cfg.tx_ant = tx_ant;
        ant_cfg.rx_ant = rx_ant;
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_ANTENNA,
-                                    HostCmd_ACT_GEN_SET, 0, &ant_cfg);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_RF_ANTENNA,
+                               HostCmd_ACT_GEN_SET, 0, &ant_cfg, true);
 }
 
 /* cfg80211 operation handler for stop ap.
@@ -1349,8 +1372,8 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 
        priv->ap_11n_enabled = 0;
 
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
-                                 HostCmd_ACT_GEN_SET, 0, NULL)) {
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+                            HostCmd_ACT_GEN_SET, 0, NULL, true)) {
                wiphy_err(wiphy, "Failed to stop the BSS\n");
                return -1;
        }
@@ -1461,16 +1484,16 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
                bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout;
        }
 
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
-                                 HostCmd_ACT_GEN_SET, 0, NULL)) {
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+                            HostCmd_ACT_GEN_SET, 0, NULL, true)) {
                wiphy_err(wiphy, "Failed to stop the BSS\n");
                kfree(bss_cfg);
                return -1;
        }
 
-       if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
-                                  HostCmd_ACT_GEN_SET,
-                                  UAP_BSS_PARAMS_I, bss_cfg)) {
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+                            HostCmd_ACT_GEN_SET,
+                            UAP_BSS_PARAMS_I, bss_cfg, false)) {
                wiphy_err(wiphy, "Failed to set the SSID\n");
                kfree(bss_cfg);
                return -1;
@@ -1478,8 +1501,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
 
        kfree(bss_cfg);
 
-       if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START,
-                                  HostCmd_ACT_GEN_SET, 0, NULL)) {
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
+                            HostCmd_ACT_GEN_SET, 0, NULL, false)) {
                wiphy_err(wiphy, "Failed to start the BSS\n");
                return -1;
        }
@@ -1489,9 +1512,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
        else
                priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
 
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
-                                 HostCmd_ACT_GEN_SET, 0,
-                                 &priv->curr_pkt_filter))
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+                            HostCmd_ACT_GEN_SET, 0,
+                            &priv->curr_pkt_filter, true))
                return -1;
 
        return 0;
@@ -2097,8 +2120,8 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
        ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
        ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
 
-       rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
-       /* Set MCS for 1x1 */
+       rx_mcs_supp = GET_RXMCSSUPP(adapter->user_dev_mcs_support);
+       /* Set MCS for 1x1/2x2 */
        memset(mcs, 0xff, rx_mcs_supp);
        /* Clear all the other values */
        memset(&mcs[rx_mcs_supp], 0,
@@ -2459,9 +2482,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
                                   MWIFIEX_CRITERIA_UNICAST |
                                   MWIFIEX_CRITERIA_MULTICAST;
 
-       ret =  mwifiex_send_cmd_sync(priv, HostCmd_CMD_MEF_CFG,
-                                    HostCmd_ACT_GEN_SET, 0,
-                                    &mef_cfg);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG,
+                              HostCmd_ACT_GEN_SET, 0, &mef_cfg, true);
 
        kfree(mef_entry);
        return ret;
@@ -2573,9 +2595,9 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
        if (!coalesce) {
                dev_dbg(adapter->dev,
                        "Disable coalesce and reset all previous rules\n");
-               return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG,
-                                            HostCmd_ACT_GEN_SET, 0,
-                                            &coalesce_cfg);
+               return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG,
+                                       HostCmd_ACT_GEN_SET, 0,
+                                       &coalesce_cfg, true);
        }
 
        coalesce_cfg.num_of_rules = coalesce->n_rules;
@@ -2590,8 +2612,8 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
                }
        }
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG,
-                                    HostCmd_ACT_GEN_SET, 0, &coalesce_cfg);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG,
+                               HostCmd_ACT_GEN_SET, 0, &coalesce_cfg, true);
 }
 
 /* cfg80211 ops handler for tdls_mgmt.
@@ -2600,8 +2622,8 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
 static int
 mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
                           u8 *peer, u8 action_code, u8 dialog_token,
-                          u16 status_code, const u8 *extra_ies,
-                          size_t extra_ies_len)
+                          u16 status_code, u32 peer_capability,
+                          const u8 *extra_ies, size_t extra_ies_len)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
        int ret;
@@ -2908,7 +2930,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
 
        wiphy->features |= NL80211_FEATURE_HT_IBSS |
                           NL80211_FEATURE_INACTIVITY_TIMER |
-                          NL80211_FEATURE_LOW_PRIORITY_SCAN;
+                          NL80211_FEATURE_LOW_PRIORITY_SCAN |
+                          NL80211_FEATURE_NEED_OBSS_SCAN;
 
        /* Reserve space for mwifiex specific private data for BSS */
        wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
@@ -2939,17 +2962,17 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
                                   country_code);
        }
 
-       mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
-                             HostCmd_ACT_GEN_GET, FRAG_THRESH_I, &thr);
+       mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                        HostCmd_ACT_GEN_GET, FRAG_THRESH_I, &thr, true);
        wiphy->frag_threshold = thr;
-       mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
-                             HostCmd_ACT_GEN_GET, RTS_THRESH_I, &thr);
+       mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                        HostCmd_ACT_GEN_GET, RTS_THRESH_I, &thr, true);
        wiphy->rts_threshold = thr;
-       mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
-                             HostCmd_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry);
+       mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                        HostCmd_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry, true);
        wiphy->retry_short = (u8) retry;
-       mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
-                             HostCmd_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry);
+       mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                        HostCmd_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry, true);
        wiphy->retry_long = (u8) retry;
 
        adapter->wiphy = wiphy;
index 2c3226bf86f89302716cd30178d76ba54697d869..0ddec3d4b059cbd7d03221578035d5b1721db9b2 100644 (file)
@@ -253,7 +253,7 @@ u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
                               u8 index, u8 ht_info)
 {
        u32 mcs_num_supp =
-               (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
+               (priv->adapter->user_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
        u32 rate;
 
        if (priv->adapter->is_hw_11ac_capable)
index 21544602043cd11d346ce0f5bc4dc5c4252bea6b..14e05c9f4663dadcef536a3aa1ca3777ee0bd0aa 100644 (file)
 static void
 mwifiex_init_cmd_node(struct mwifiex_private *priv,
                      struct cmd_ctrl_node *cmd_node,
-                     u32 cmd_oid, void *data_buf)
+                     u32 cmd_oid, void *data_buf, bool sync)
 {
        cmd_node->priv = priv;
        cmd_node->cmd_oid = cmd_oid;
-       if (priv->adapter->cmd_wait_q_required) {
-               cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
-               priv->adapter->cmd_wait_q_required = false;
+       if (sync) {
+               cmd_node->wait_q_enabled = true;
                cmd_node->cmd_wait_q_woken = false;
                cmd_node->condition = &cmd_node->cmd_wait_q_woken;
        }
@@ -166,8 +165,10 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
                dev_err(adapter->dev,
                        "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
                        cmd_code);
-               mwifiex_complete_cmd(adapter, cmd_node);
+               if (cmd_node->wait_q_enabled)
+                       mwifiex_complete_cmd(adapter, cmd_node);
                mwifiex_recycle_cmd_node(adapter, cmd_node);
+               queue_work(adapter->workqueue, &adapter->main_work);
                return -1;
        }
 
@@ -480,28 +481,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
 }
 
 /*
- * This function is used to send synchronous command to the firmware.
- *
- * it allocates a wait queue for the command and wait for the command
- * response.
- */
-int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
-                         u16 cmd_action, u32 cmd_oid, void *data_buf)
-{
-       int ret = 0;
-       struct mwifiex_adapter *adapter = priv->adapter;
-
-       adapter->cmd_wait_q_required = true;
-
-       ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,
-                                    data_buf);
-
-       return ret;
-}
-
-
-/*
- * This function prepares a command and asynchronously send it to the firmware.
+ * This function prepares a command and send it to the firmware.
  *
  * Preparation includes -
  *      - Sanity tests to make sure the card is still present or the FW
@@ -511,8 +491,8 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
  *      - Fill up the non-default parameters and buffer pointers
  *      - Add the command to pending queue
  */
-int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
-                          u16 cmd_action, u32 cmd_oid, void *data_buf)
+int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
+                    u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync)
 {
        int ret;
        struct mwifiex_adapter *adapter = priv->adapter;
@@ -534,6 +514,11 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
                return -1;
        }
 
+       if (adapter->is_cmd_timedout) {
+               dev_err(adapter->dev, "PREP_CMD: FW is in bad state\n");
+               return -1;
+       }
+
        if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) {
                if (cmd_no != HostCmd_CMD_FUNC_INIT) {
                        dev_err(adapter->dev, "PREP_CMD: FW in reset state\n");
@@ -550,7 +535,7 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
        }
 
        /* Initialize the command node */
-       mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf);
+       mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf, sync);
 
        if (!cmd_node->cmd_skb) {
                dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n");
@@ -786,7 +771,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
        unsigned long flags;
 
        /* Now we got response from FW, cancel the command timer */
-       del_timer(&adapter->cmd_timer);
+       del_timer_sync(&adapter->cmd_timer);
 
        if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
                resp = (struct host_cmd_ds_command *) adapter->upld_buf;
@@ -795,7 +780,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
                return -1;
        }
 
-       adapter->num_cmd_timeout = 0;
+       adapter->is_cmd_timedout = 0;
 
        resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data;
        if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
@@ -906,8 +891,7 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
        struct cmd_ctrl_node *cmd_node;
        struct timeval tstamp;
 
-       adapter->num_cmd_timeout++;
-       adapter->dbg.num_cmd_timeout++;
+       adapter->is_cmd_timedout = 1;
        if (!adapter->curr_cmd) {
                dev_dbg(adapter->dev, "cmd: empty curr_cmd\n");
                return;
@@ -930,8 +914,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
                dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n",
                        adapter->dbg.num_cmd_host_to_card_failure);
 
-               dev_err(adapter->dev, "num_cmd_timeout = %d\n",
-                       adapter->dbg.num_cmd_timeout);
+               dev_err(adapter->dev, "is_cmd_timedout = %d\n",
+                       adapter->is_cmd_timedout);
                dev_err(adapter->dev, "num_tx_timeout = %d\n",
                        adapter->dbg.num_tx_timeout);
 
@@ -988,7 +972,9 @@ void
 mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
 {
        struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
-       unsigned long flags;
+       unsigned long flags, cmd_flags;
+       struct mwifiex_private *priv;
+       int i;
 
        /* Cancel current cmd */
        if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) {
@@ -1028,9 +1014,21 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
        }
        spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
 
-       spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
-       adapter->scan_processing = false;
-       spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+       if (adapter->scan_processing) {
+               spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+               adapter->scan_processing = false;
+               spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+               for (i = 0; i < adapter->priv_num; i++) {
+                       priv = adapter->priv[i];
+                       if (!priv)
+                               continue;
+                       if (priv->scan_request) {
+                               dev_dbg(adapter->dev, "info: aborting scan\n");
+                               cfg80211_scan_done(priv->scan_request, 1);
+                               priv->scan_request = NULL;
+                       }
+               }
+       }
 }
 
 /*
@@ -1049,7 +1047,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
        struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
        unsigned long cmd_flags;
        unsigned long scan_pending_q_flags;
-       bool cancel_scan_cmd = false;
+       struct mwifiex_private *priv;
+       int i;
 
        if ((adapter->curr_cmd) &&
            (adapter->curr_cmd->wait_q_enabled)) {
@@ -1075,15 +1074,24 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
                mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
                spin_lock_irqsave(&adapter->scan_pending_q_lock,
                                  scan_pending_q_flags);
-               cancel_scan_cmd = true;
        }
        spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
                               scan_pending_q_flags);
 
-       if (cancel_scan_cmd) {
+       if (adapter->scan_processing) {
                spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
                adapter->scan_processing = false;
                spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+               for (i = 0; i < adapter->priv_num; i++) {
+                       priv = adapter->priv[i];
+                       if (!priv)
+                               continue;
+                       if (priv->scan_request) {
+                               dev_dbg(adapter->dev, "info: aborting scan\n");
+                               cfg80211_scan_done(priv->scan_request, 1);
+                               priv->scan_request = NULL;
+                       }
+               }
        }
        adapter->cmd_wait_q.status = -1;
 }
@@ -1584,6 +1592,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
 
        adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap);
        adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support;
+       adapter->user_dev_mcs_support = adapter->hw_dev_mcs_support;
 
        if (adapter->if_ops.update_mp_end_port)
                adapter->if_ops.update_mp_end_port(adapter,
index a5f9875cfd6e311f7e87b40890538ee312b37f4b..b8a49aad12fd662434ce2a29aaa8edecfb52ba0b 100644 (file)
@@ -85,8 +85,8 @@ static struct mwifiex_debug_data items[] = {
         item_addr(hs_activated), 1},
        {"num_tx_timeout", item_size(num_tx_timeout),
         item_addr(num_tx_timeout), 1},
-       {"num_cmd_timeout", item_size(num_cmd_timeout),
-        item_addr(num_cmd_timeout), 1},
+       {"is_cmd_timedout", item_size(is_cmd_timedout),
+        item_addr(is_cmd_timedout), 1},
        {"timeout_cmd_id", item_size(timeout_cmd_id),
         item_addr(timeout_cmd_id), 1},
        {"timeout_cmd_act", item_size(timeout_cmd_act),
@@ -493,7 +493,7 @@ mwifiex_regrdwr_write(struct file *file,
 {
        unsigned long addr = get_zeroed_page(GFP_KERNEL);
        char *buf = (char *) addr;
-       size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
+       size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
        int ret;
        u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
 
@@ -594,7 +594,7 @@ mwifiex_rdeeprom_write(struct file *file,
 {
        unsigned long addr = get_zeroed_page(GFP_KERNEL);
        char *buf = (char *) addr;
-       size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
+       size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
        int ret = 0;
        int offset = -1, bytes = -1;
 
index aa8abef583498a594da6a2fc01fc1013a1dfc1f0..39cb3542f79cdf777ccc9528e4ddb76768e5c89a 100644 (file)
@@ -236,8 +236,21 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
  */
 #define MWIFIEX_FW_DEF_HTTXCFG (BIT(1) | BIT(4) | BIT(5) | BIT(6))
 
+/* 11AC Tx and Rx MCS map for 1x1 mode:
+ * IEEE80211_VHT_MCS_SUPPORT_0_9 for stream 1
+ * IEEE80211_VHT_MCS_NOT_SUPPORTED for remaining 7 streams
+ */
+#define MWIFIEX_11AC_MCS_MAP_1X1       0xfffefffe
+
+/* 11AC Tx and Rx MCS map for 2x2 mode:
+ * IEEE80211_VHT_MCS_SUPPORT_0_9 for stream 1 and 2
+ * IEEE80211_VHT_MCS_NOT_SUPPORTED for remaining 6 streams
+ */
+#define MWIFIEX_11AC_MCS_MAP_2X2       0xfffafffa
+
 #define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
 #define SETHT_MCS32(x) (x[4] |= 1)
+#define HT_STREAM_1X1  0x11
 #define HT_STREAM_2X2  0x22
 
 #define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4))
index 81ac001ee74187d325f7a7d166666f9ec3c497fa..3bf3d58bbc029b0a48a937a0c65d15a83552b295 100644 (file)
@@ -138,9 +138,9 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
        }
 
        if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
-               return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
-                                             HostCmd_ACT_GEN_SET,
-                                             UAP_CUSTOM_IE_I, ie_list);
+               return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+                                       HostCmd_ACT_GEN_SET,
+                                       UAP_CUSTOM_IE_I, ie_list, false);
 
        return 0;
 }
index a4cd2cb066edf96ee2e57b006ad25e205535891f..4ecd0b208ac64f5be6ffa75b9f15a1be965250a2 100644 (file)
@@ -234,7 +234,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
 
        adapter->pm_wakeup_fw_try = false;
 
-       adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
        adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 
        adapter->is_hs_configured = false;
@@ -620,7 +619,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
        /* cancel current command */
        if (adapter->curr_cmd) {
                dev_warn(adapter->dev, "curr_cmd is still in processing\n");
-               del_timer(&adapter->cmd_timer);
+               del_timer_sync(&adapter->cmd_timer);
                mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
                adapter->curr_cmd = NULL;
        }
index 5974642f38b1915db2277c2bc6f1fe4885a958f1..1fb2212079aebac25cde7dd78bf9792ccf74de39 100644 (file)
@@ -209,7 +209,7 @@ struct mwifiex_debug_info {
        u32 num_cmd_assoc_success;
        u32 num_cmd_assoc_failure;
        u32 num_tx_timeout;
-       u32 num_cmd_timeout;
+       u8 is_cmd_timedout;
        u16 timeout_cmd_id;
        u16 timeout_cmd_act;
        u16 last_cmd_id[DBG_CMD_NUM];
index 34472ea53841631ab2bed073c8cb4fe6c7e7009b..89dc62a467f4d2ba8b7cc2fcf6b7d1d63b058f68 100644 (file)
@@ -901,9 +901,9 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
        mwifiex_get_active_data_rates(priv, adhoc_start->data_rate);
        if ((adapter->adhoc_start_band & BAND_G) &&
            (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
-               if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
-                                          HostCmd_ACT_GEN_SET, 0,
-                                          &priv->curr_pkt_filter)) {
+               if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+                                    HostCmd_ACT_GEN_SET, 0,
+                                    &priv->curr_pkt_filter, false)) {
                        dev_err(adapter->dev,
                                "ADHOC_S_CMD: G Protection config failed\n");
                        return -1;
@@ -1073,9 +1073,9 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
                        priv->
                        curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
 
-               if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
-                                          HostCmd_ACT_GEN_SET, 0,
-                                          &curr_pkt_filter)) {
+               if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+                                    HostCmd_ACT_GEN_SET, 0,
+                                    &curr_pkt_filter, false)) {
                        dev_err(priv->adapter->dev,
                                "ADHOC_J_CMD: G Protection config failed\n");
                        return -1;
@@ -1312,8 +1312,8 @@ int mwifiex_associate(struct mwifiex_private *priv,
           retrieval */
        priv->assoc_rsp_size = 0;
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE,
-                                   HostCmd_ACT_GEN_SET, 0, bss_desc);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE,
+                               HostCmd_ACT_GEN_SET, 0, bss_desc, true);
 }
 
 /*
@@ -1338,8 +1338,8 @@ mwifiex_adhoc_start(struct mwifiex_private *priv,
        else
                mwifiex_set_ba_params(priv);
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START,
-                                   HostCmd_ACT_GEN_SET, 0, adhoc_ssid);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START,
+                               HostCmd_ACT_GEN_SET, 0, adhoc_ssid, true);
 }
 
 /*
@@ -1383,8 +1383,8 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
        dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
                priv->curr_bss_params.band);
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
-                                   HostCmd_ACT_GEN_SET, 0, bss_desc);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
+                               HostCmd_ACT_GEN_SET, 0, bss_desc, true);
 }
 
 /*
@@ -1403,8 +1403,8 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
        else
                memcpy(mac_address, mac, ETH_ALEN);
 
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
-                                   HostCmd_ACT_GEN_SET, 0, mac_address);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
+                              HostCmd_ACT_GEN_SET, 0, mac_address, true);
 
        return ret;
 }
@@ -1432,19 +1432,31 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
                                              GFP_KERNEL);
                break;
        case NL80211_IFTYPE_ADHOC:
-               return mwifiex_send_cmd_sync(priv,
-                                            HostCmd_CMD_802_11_AD_HOC_STOP,
-                                            HostCmd_ACT_GEN_SET, 0, NULL);
+               return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
+                                       HostCmd_ACT_GEN_SET, 0, NULL, true);
        case NL80211_IFTYPE_AP:
-               return mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
-                                            HostCmd_ACT_GEN_SET, 0, NULL);
+               return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+                                       HostCmd_ACT_GEN_SET, 0, NULL, true);
        default:
                break;
        }
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(mwifiex_deauthenticate);
+
+/* This function deauthenticates/disconnects from all BSS. */
+void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter)
+{
+       struct mwifiex_private *priv;
+       int i;
+
+       for (i = 0; i < adapter->priv_num; i++) {
+               priv = adapter->priv[i];
+               if (priv)
+                       mwifiex_deauthenticate(priv, NULL);
+       }
+}
+EXPORT_SYMBOL_GPL(mwifiex_deauthenticate_all);
 
 /*
  * This function converts band to radio type used in channel TLV.
index 9d3d2758ec355381ebaceea681e3fd2ebae5d753..7b4502fefec388050d845df770550ae540acb0de 100644 (file)
@@ -194,7 +194,7 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
        if (adapter->if_ops.cleanup_if)
                adapter->if_ops.cleanup_if(adapter);
 
-       del_timer(&adapter->cmd_timer);
+       del_timer_sync(&adapter->cmd_timer);
 
        /* Free private structures */
        for (i = 0; i < adapter->priv_num; i++) {
@@ -678,8 +678,8 @@ mwifiex_set_mac_address(struct net_device *dev, void *addr)
        memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN);
 
        /* Send request to firmware */
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
-                                   HostCmd_ACT_GEN_SET, 0, NULL);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
+                              HostCmd_ACT_GEN_SET, 0, NULL, true);
 
        if (!ret)
                memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
@@ -871,7 +871,6 @@ mwifiex_add_card(void *card, struct semaphore *sem,
        adapter->is_suspended = false;
        adapter->hs_activated = false;
        init_waitqueue_head(&adapter->hs_activate_wait_q);
-       adapter->cmd_wait_q_required = false;
        init_waitqueue_head(&adapter->cmd_wait_q.wait);
        adapter->cmd_wait_q.status = 0;
        adapter->scan_wait_q_woken = false;
index 407f8eada720df2a71bb89a37d5cceba6b34de61..f0289c12e041a066ea68f9153787e135c64a0376 100644 (file)
@@ -145,7 +145,6 @@ struct mwifiex_dbg {
        u32 num_cmd_assoc_success;
        u32 num_cmd_assoc_failure;
        u32 num_tx_timeout;
-       u32 num_cmd_timeout;
        u16 timeout_cmd_id;
        u16 timeout_cmd_act;
        u16 last_cmd_id[DBG_CMD_NUM];
@@ -575,6 +574,7 @@ struct mwifiex_rx_reorder_tbl {
        struct list_head list;
        int tid;
        u8 ta[ETH_ALEN];
+       int init_win;
        int start_win;
        int win_size;
        void **rx_reorder_ptr;
@@ -719,7 +719,7 @@ struct mwifiex_adapter {
        struct cmd_ctrl_node *curr_cmd;
        /* spin lock for command */
        spinlock_t mwifiex_cmd_lock;
-       u32 num_cmd_timeout;
+       u8 is_cmd_timedout;
        u16 last_init_cmd;
        struct timer_list cmd_timer;
        struct list_head cmd_free_q;
@@ -773,12 +773,12 @@ struct mwifiex_adapter {
        u8 event_body[MAX_EVENT_SIZE];
        u32 hw_dot_11n_dev_cap;
        u8 hw_dev_mcs_support;
+       u8 user_dev_mcs_support;
        u8 adhoc_11n_enabled;
        u8 sec_chan_offset;
        struct mwifiex_dbg dbg;
        u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
        u32 arp_filter_size;
-       u16 cmd_wait_q_required;
        struct mwifiex_wait_queue cmd_wait_q;
        u8 scan_wait_q_woken;
        spinlock_t queue_lock;          /* lock for tx queues */
@@ -838,11 +838,8 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter);
 int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
                         struct cmd_ctrl_node *cmd_node);
 
-int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
-                          u16 cmd_action, u32 cmd_oid, void *data_buf);
-
-int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
-                         u16 cmd_action, u32 cmd_oid, void *data_buf);
+int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
+                    u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync);
 
 void mwifiex_cmd_timeout_func(unsigned long function_context);
 
@@ -930,6 +927,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
 void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason);
 u8 mwifiex_band_to_radio_type(u8 band);
 int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac);
+void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter);
 int mwifiex_adhoc_start(struct mwifiex_private *priv,
                        struct cfg80211_ssid *adhoc_ssid);
 int mwifiex_adhoc_join(struct mwifiex_private *priv,
index d11d4acf089022888f8996381c38bd452ae0691f..9f1683b5f28f8e7c385751c8a34b239b2c2ff903 100644 (file)
@@ -190,6 +190,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
                card->pcie.firmware = data->firmware;
                card->pcie.reg = data->reg;
                card->pcie.blksz_fw_dl = data->blksz_fw_dl;
+               card->pcie.tx_buf_size = data->tx_buf_size;
        }
 
        if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
@@ -210,7 +211,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        struct pcie_service_card *card;
        struct mwifiex_adapter *adapter;
        struct mwifiex_private *priv;
-       int i;
 
        card = pci_get_drvdata(pdev);
        if (!card)
@@ -229,11 +229,7 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
                        mwifiex_pcie_resume(&pdev->dev);
 #endif
 
-               for (i = 0; i < adapter->priv_num; i++)
-                       if ((GET_BSS_ROLE(adapter->priv[i]) ==
-                            MWIFIEX_BSS_ROLE_STA) &&
-                           adapter->priv[i]->media_connected)
-                               mwifiex_deauthenticate(adapter->priv[i], NULL);
+               mwifiex_deauthenticate_all(adapter);
 
                priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
 
@@ -1217,6 +1213,12 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
                rd_index = card->rxbd_rdptr & reg->rx_mask;
                skb_data = card->rx_buf_list[rd_index];
 
+               /* If skb allocation was failed earlier for Rx packet,
+                * rx_buf_list[rd_index] would have been left with a NULL.
+                */
+               if (!skb_data)
+                       return -ENOMEM;
+
                mwifiex_unmap_pci_memory(adapter, skb_data, PCI_DMA_FROMDEVICE);
                card->rx_buf_list[rd_index] = NULL;
 
@@ -1529,6 +1531,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
                if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
                        mwifiex_process_sleep_confirm_resp(adapter, skb->data,
                                                           skb->len);
+                       mwifiex_pcie_enable_host_int(adapter);
+                       if (mwifiex_write_reg(adapter,
+                                             PCIE_CPU_INT_EVENT,
+                                             CPU_INTR_SLEEP_CFM_DONE)) {
+                               dev_warn(adapter->dev,
+                                        "Write register failed\n");
+                               return -1;
+                       }
                        while (reg->sleep_cookie && (count++ < 10) &&
                               mwifiex_pcie_ok_to_access_hw(adapter))
                                usleep_range(50, 60);
@@ -1975,23 +1985,9 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
                adapter->int_status |= pcie_ireg;
                spin_unlock_irqrestore(&adapter->int_lock, flags);
 
-               if (pcie_ireg & HOST_INTR_CMD_DONE) {
-                       if ((adapter->ps_state == PS_STATE_SLEEP_CFM) ||
-                           (adapter->ps_state == PS_STATE_SLEEP)) {
-                               mwifiex_pcie_enable_host_int(adapter);
-                               if (mwifiex_write_reg(adapter,
-                                                     PCIE_CPU_INT_EVENT,
-                                                     CPU_INTR_SLEEP_CFM_DONE)
-                                                     ) {
-                                       dev_warn(adapter->dev,
-                                                "Write register failed\n");
-                                       return;
-
-                               }
-                       }
-               } else if (!adapter->pps_uapsd_mode &&
-                          adapter->ps_state == PS_STATE_SLEEP &&
-                          mwifiex_pcie_ok_to_access_hw(adapter)) {
+               if (!adapter->pps_uapsd_mode &&
+                   adapter->ps_state == PS_STATE_SLEEP &&
+                   mwifiex_pcie_ok_to_access_hw(adapter)) {
                                /* Potentially for PCIe we could get other
                                 * interrupts like shared. Don't change power
                                 * state until cookie is set */
@@ -2320,6 +2316,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
        }
 
        adapter->dev = &pdev->dev;
+       adapter->tx_buf_size = card->pcie.tx_buf_size;
        strcpy(adapter->fw_name, card->pcie.firmware);
 
        return 0;
index d322ab8604ea806e8216ab122d1ae30df6cc618d..193af75bf5828a798adf55de6124854f05011fc5 100644 (file)
@@ -195,18 +195,21 @@ struct mwifiex_pcie_device {
        const char *firmware;
        const struct mwifiex_pcie_card_reg *reg;
        u16 blksz_fw_dl;
+       u16 tx_buf_size;
 };
 
 static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
        .firmware       = PCIE8766_DEFAULT_FW_NAME,
        .reg            = &mwifiex_reg_8766,
        .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+       .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
 };
 
 static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
        .firmware       = PCIE8897_DEFAULT_FW_NAME,
        .reg            = &mwifiex_reg_8897,
        .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+       .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
 };
 
 struct mwifiex_evt_buf_desc {
index 92adbb1ebabc1e3bd61e2af9c740c7470d4acb85..f13924447a2cd507496ffc26992243596839809e 100644 (file)
@@ -738,8 +738,8 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
                else
                        cmd_no = HostCmd_CMD_802_11_SCAN;
 
-               ret = mwifiex_send_cmd_async(priv, cmd_no, HostCmd_ACT_GEN_SET,
-                                            0, scan_cfg_out);
+               ret = mwifiex_send_cmd(priv, cmd_no, HostCmd_ACT_GEN_SET,
+                                      0, scan_cfg_out, false);
 
                /* rate IE is updated per scan command but same starting
                 * pointer is used each time so that rate IE from earlier
@@ -2311,12 +2311,12 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
                         curr_bss->ht_info_offset);
 
        if (curr_bss->bcn_vht_cap)
-               curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf +
-                                               curr_bss->vht_cap_offset);
+               curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf +
+                                                curr_bss->vht_cap_offset);
 
        if (curr_bss->bcn_vht_oper)
-               curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf +
-                                                curr_bss->vht_info_offset);
+               curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf +
+                                                 curr_bss->vht_info_offset);
 
        if (curr_bss->bcn_bss_co_2040)
                curr_bss->bcn_bss_co_2040 =
index b44a31523461e2c5ba7d768c941fc0934abaacb6..e0dcd3ed7a69d01d1a5342be587a8901e2b34b57 100644 (file)
@@ -84,6 +84,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
                card->mp_agg_pkt_limit = data->mp_agg_pkt_limit;
                card->supports_sdio_new_mode = data->supports_sdio_new_mode;
                card->has_control_mask = data->has_control_mask;
+               card->tx_buf_size = data->tx_buf_size;
        }
 
        sdio_claim_host(func);
@@ -165,7 +166,6 @@ mwifiex_sdio_remove(struct sdio_func *func)
        struct sdio_mmc_card *card;
        struct mwifiex_adapter *adapter;
        struct mwifiex_private *priv;
-       int i;
 
        pr_debug("info: SDIO func num=%d\n", func->num);
 
@@ -184,11 +184,7 @@ mwifiex_sdio_remove(struct sdio_func *func)
                if (adapter->is_suspended)
                        mwifiex_sdio_resume(adapter->dev);
 
-               for (i = 0; i < adapter->priv_num; i++)
-                       if ((GET_BSS_ROLE(adapter->priv[i]) ==
-                                               MWIFIEX_BSS_ROLE_STA) &&
-                           adapter->priv[i]->media_connected)
-                               mwifiex_deauthenticate(adapter->priv[i], NULL);
+               mwifiex_deauthenticate_all(adapter);
 
                priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
                mwifiex_disable_auto_ds(priv);
@@ -1760,6 +1756,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 
        /* save adapter pointer in card */
        card->adapter = adapter;
+       adapter->tx_buf_size = card->tx_buf_size;
 
        sdio_claim_host(func);
 
index 532ae0ac4dfb3e40bb12592db32ec94e702a4c2b..c71201b2e2a333c20f926bacb4842395230c6926 100644 (file)
@@ -233,6 +233,7 @@ struct sdio_mmc_card {
        u8 mp_agg_pkt_limit;
        bool supports_sdio_new_mode;
        bool has_control_mask;
+       u16 tx_buf_size;
 
        u32 mp_rd_bitmap;
        u32 mp_wr_bitmap;
@@ -256,6 +257,7 @@ struct mwifiex_sdio_device {
        u8 mp_agg_pkt_limit;
        bool supports_sdio_new_mode;
        bool has_control_mask;
+       u16 tx_buf_size;
 };
 
 static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = {
@@ -312,6 +314,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
        .mp_agg_pkt_limit = 8,
        .supports_sdio_new_mode = false,
        .has_control_mask = true,
+       .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
 };
 
 static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
@@ -321,6 +324,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
        .mp_agg_pkt_limit = 8,
        .supports_sdio_new_mode = false,
        .has_control_mask = true,
+       .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
 };
 
 static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
@@ -330,6 +334,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
        .mp_agg_pkt_limit = 8,
        .supports_sdio_new_mode = false,
        .has_control_mask = true,
+       .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
 };
 
 static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
@@ -339,6 +344,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
        .mp_agg_pkt_limit = 16,
        .supports_sdio_new_mode = true,
        .has_control_mask = false,
+       .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
 };
 
 /*
index 5aa3d39e48bcde8c962f5ce3311cac7c142afb0d..4315a3ba3b92377ff10d95cf7079dfaa3886c91b 100644 (file)
@@ -1411,9 +1411,9 @@ int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
                /* 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);
+                       ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA,
+                                              HostCmd_ACT_GEN_SET, 0,
+                                              prop, true);
                        if (ret)
                                return ret;
                }
@@ -1912,15 +1912,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
 
        if (first_sta) {
                if (priv->adapter->iface_type == MWIFIEX_PCIE) {
-                       ret = mwifiex_send_cmd_sync(priv,
-                                               HostCmd_CMD_PCIE_DESC_DETAILS,
-                                               HostCmd_ACT_GEN_SET, 0, NULL);
+                       ret = mwifiex_send_cmd(priv,
+                                              HostCmd_CMD_PCIE_DESC_DETAILS,
+                                              HostCmd_ACT_GEN_SET, 0, NULL,
+                                              true);
                        if (ret)
                                return -1;
                }
 
-               ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_FUNC_INIT,
-                                           HostCmd_ACT_GEN_SET, 0, NULL);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_FUNC_INIT,
+                                      HostCmd_ACT_GEN_SET, 0, NULL, true);
                if (ret)
                        return -1;
 
@@ -1938,55 +1939,57 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
                }
 
                if (adapter->cal_data) {
-                       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
-                                               HostCmd_ACT_GEN_SET, 0, NULL);
+                       ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA,
+                                              HostCmd_ACT_GEN_SET, 0, NULL,
+                                              true);
                        if (ret)
                                return -1;
                }
 
                /* Read MAC address from HW */
-               ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_GET_HW_SPEC,
-                                           HostCmd_ACT_GEN_GET, 0, NULL);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_GET_HW_SPEC,
+                                      HostCmd_ACT_GEN_GET, 0, NULL, true);
                if (ret)
                        return -1;
 
                /* Reconfigure tx buf size */
-               ret = mwifiex_send_cmd_sync(priv,
-                                           HostCmd_CMD_RECONFIGURE_TX_BUFF,
-                                           HostCmd_ACT_GEN_SET, 0,
-                                           &priv->adapter->tx_buf_size);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+                                      HostCmd_ACT_GEN_SET, 0,
+                                      &priv->adapter->tx_buf_size, true);
                if (ret)
                        return -1;
 
                if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
                        /* Enable IEEE PS by default */
                        priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
-                       ret = mwifiex_send_cmd_sync(
-                                       priv, HostCmd_CMD_802_11_PS_MODE_ENH,
-                                       EN_AUTO_PS, BITMAP_STA_PS, NULL);
+                       ret = mwifiex_send_cmd(priv,
+                                              HostCmd_CMD_802_11_PS_MODE_ENH,
+                                              EN_AUTO_PS, BITMAP_STA_PS, NULL,
+                                              true);
                        if (ret)
                                return -1;
                }
        }
 
        /* get tx rate */
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
-                                   HostCmd_ACT_GEN_GET, 0, NULL);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
+                              HostCmd_ACT_GEN_GET, 0, NULL, true);
        if (ret)
                return -1;
        priv->data_rate = 0;
 
        /* get tx power */
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_TX_PWR,
-                                   HostCmd_ACT_GEN_GET, 0, NULL);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR,
+                              HostCmd_ACT_GEN_GET, 0, NULL, true);
        if (ret)
                return -1;
 
        if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
                /* set ibss coalescing_status */
-               ret = mwifiex_send_cmd_sync(
-                               priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
-                               HostCmd_ACT_GEN_SET, 0, &enable);
+               ret = mwifiex_send_cmd(
+                               priv,
+                               HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+                               HostCmd_ACT_GEN_SET, 0, &enable, true);
                if (ret)
                        return -1;
        }
@@ -1994,16 +1997,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
        memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
        amsdu_aggr_ctrl.enable = true;
        /* Send request to firmware */
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
-                                   HostCmd_ACT_GEN_SET, 0,
-                                   &amsdu_aggr_ctrl);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
+                              HostCmd_ACT_GEN_SET, 0,
+                              &amsdu_aggr_ctrl, true);
        if (ret)
                return -1;
        /* MAC Control must be the last command in init_fw */
        /* set MAC Control */
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
-                                   HostCmd_ACT_GEN_SET, 0,
-                                   &priv->curr_pkt_filter);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+                              HostCmd_ACT_GEN_SET, 0,
+                              &priv->curr_pkt_filter, true);
        if (ret)
                return -1;
 
@@ -2012,10 +2015,9 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
                /* Enable auto deep sleep */
                auto_ds.auto_ds = DEEP_SLEEP_ON;
                auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
-               ret = mwifiex_send_cmd_sync(priv,
-                                           HostCmd_CMD_802_11_PS_MODE_ENH,
-                                           EN_AUTO_PS, BITMAP_AUTO_DS,
-                                           &auto_ds);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+                                      EN_AUTO_PS, BITMAP_AUTO_DS,
+                                      &auto_ds, true);
                if (ret)
                        return -1;
        }
@@ -2023,9 +2025,9 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
        if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
                /* Send cmd to FW to enable/disable 11D function */
                state_11d = ENABLE_11D;
-               ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
-                                           HostCmd_ACT_GEN_SET, DOT11D_I,
-                                           &state_11d);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                                      HostCmd_ACT_GEN_SET, DOT11D_I,
+                                      &state_11d, true);
                if (ret)
                        dev_err(priv->adapter->dev,
                                "11D: failed to enable 11D\n");
@@ -2038,8 +2040,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
         * (Short GI, Channel BW, Green field support etc.) for transmit
         */
        tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG;
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_11N_CFG,
-                                   HostCmd_ACT_GEN_SET, 0, &tx_cfg);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG,
+                              HostCmd_ACT_GEN_SET, 0, &tx_cfg, true);
 
        ret = -EINPROGRESS;
 
index 1c5e18804074a0c61e30c1cb9a2ef5f4f9868141..a8f7d545e22a94eb4365a534cb8018307f434136 100644 (file)
@@ -158,8 +158,8 @@ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
 
        priv->subsc_evt_rssi_state = EVENT_HANDLED;
 
-       mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
-                              0, 0, subsc_evt);
+       mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
+                        0, 0, subsc_evt, false);
 
        return 0;
 }
@@ -317,9 +317,8 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
        if (priv->is_data_rate_auto)
                priv->data_rate = 0;
        else
-               return mwifiex_send_cmd_async(priv,
-                                             HostCmd_CMD_802_11_TX_RATE_QUERY,
-                                             HostCmd_ACT_GEN_GET, 0, NULL);
+               return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+                                       HostCmd_ACT_GEN_GET, 0, NULL, false);
 
        return 0;
 }
index 92ff7b324b00d274d4225a0ae93150fe91cee384..368450cc56c7d9e19b8c2a74c47d43a9c5c91b1f 100644 (file)
@@ -116,7 +116,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
        adapter->tx_lock_flag = false;
        adapter->pps_uapsd_mode = false;
 
-       if (adapter->num_cmd_timeout && adapter->curr_cmd)
+       if (adapter->is_cmd_timedout && adapter->curr_cmd)
                return;
        priv->media_connected = false;
        dev_dbg(adapter->dev,
@@ -293,9 +293,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
        case EVENT_HS_ACT_REQ:
                dev_dbg(adapter->dev, "event: HS_ACT_REQ\n");
-               ret = mwifiex_send_cmd_async(priv,
-                                            HostCmd_CMD_802_11_HS_CFG_ENH,
-                                            0, 0, NULL);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH,
+                                      0, 0, NULL, false);
                break;
 
        case EVENT_MIC_ERR_UNICAST:
@@ -326,9 +325,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
        case EVENT_BG_SCAN_REPORT:
                dev_dbg(adapter->dev, "event: BGS_REPORT\n");
-               ret = mwifiex_send_cmd_async(priv,
-                                            HostCmd_CMD_802_11_BG_SCAN_QUERY,
-                                            HostCmd_ACT_GEN_GET, 0, NULL);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY,
+                                      HostCmd_ACT_GEN_GET, 0, NULL, false);
                break;
 
        case EVENT_PORT_RELEASE:
@@ -345,16 +343,16 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
        case EVENT_WMM_STATUS_CHANGE:
                dev_dbg(adapter->dev, "event: WMM status changed\n");
-               ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS,
-                                            0, 0, NULL);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_WMM_GET_STATUS,
+                                      0, 0, NULL, false);
                break;
 
        case EVENT_RSSI_LOW:
                cfg80211_cqm_rssi_notify(priv->netdev,
                                         NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
                                         GFP_KERNEL);
-               mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO,
-                                      HostCmd_ACT_GEN_GET, 0, NULL);
+               mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
+                                HostCmd_ACT_GEN_GET, 0, NULL, false);
                priv->subsc_evt_rssi_state = RSSI_LOW_RECVD;
                dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n");
                break;
@@ -368,8 +366,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                cfg80211_cqm_rssi_notify(priv->netdev,
                                         NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
                                         GFP_KERNEL);
-               mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO,
-                                      HostCmd_ACT_GEN_GET, 0, NULL);
+               mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
+                                HostCmd_ACT_GEN_GET, 0, NULL, false);
                priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD;
                dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n");
                break;
@@ -396,15 +394,15 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                break;
        case EVENT_IBSS_COALESCED:
                dev_dbg(adapter->dev, "event: IBSS_COALESCED\n");
-               ret = mwifiex_send_cmd_async(priv,
+               ret = mwifiex_send_cmd(priv,
                                HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
-                               HostCmd_ACT_GEN_GET, 0, NULL);
+                               HostCmd_ACT_GEN_GET, 0, NULL, false);
                break;
        case EVENT_ADDBA:
                dev_dbg(adapter->dev, "event: ADDBA Request\n");
-               mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
-                                      HostCmd_ACT_GEN_SET, 0,
-                                      adapter->event_body);
+               mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
+                                HostCmd_ACT_GEN_SET, 0,
+                                adapter->event_body, false);
                break;
        case EVENT_DELBA:
                dev_dbg(adapter->dev, "event: DELBA Request\n");
@@ -455,10 +453,10 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                priv->csa_expire_time =
                                jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME);
                priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel;
-               ret = mwifiex_send_cmd_async(priv,
-                       HostCmd_CMD_802_11_DEAUTHENTICATE,
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
                        HostCmd_ACT_GEN_SET, 0,
-                       priv->curr_bss_params.bss_descriptor.mac_address);
+                       priv->curr_bss_params.bss_descriptor.mac_address,
+                       false);
                break;
 
        default:
index b393d55b3aa0d430a010c6720bce1b6785061af0..33170af150f6da3823ad3a5743f472fc6f141c98 100644 (file)
@@ -108,19 +108,19 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
                                "info: Set multicast list=%d\n",
                                mcast_list->num_multicast_addr);
                        /* Send multicast addresses to firmware */
-                       ret = mwifiex_send_cmd_async(priv,
-                               HostCmd_CMD_MAC_MULTICAST_ADR,
-                               HostCmd_ACT_GEN_SET, 0,
-                               mcast_list);
+                       ret = mwifiex_send_cmd(priv,
+                                              HostCmd_CMD_MAC_MULTICAST_ADR,
+                                              HostCmd_ACT_GEN_SET, 0,
+                                              mcast_list, false);
                }
        }
        dev_dbg(priv->adapter->dev,
                "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
               old_pkt_filter, priv->curr_pkt_filter);
        if (old_pkt_filter != priv->curr_pkt_filter) {
-               ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
-                                            HostCmd_ACT_GEN_SET,
-                                            0, &priv->curr_pkt_filter);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+                                      HostCmd_ACT_GEN_SET,
+                                      0, &priv->curr_pkt_filter, false);
        }
 
        return ret;
@@ -237,8 +237,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
 
        rcu_read_unlock();
 
-       if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
-                                  HostCmd_ACT_GEN_SET, 0, NULL)) {
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+                            HostCmd_ACT_GEN_SET, 0, NULL, false)) {
                wiphy_err(priv->adapter->wiphy,
                          "11D: setting domain info in FW\n");
                return -1;
@@ -429,16 +429,13 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
                                status = -1;
                                break;
                        }
-                       if (cmd_type == MWIFIEX_SYNC_CMD)
-                               status = mwifiex_send_cmd_sync(priv,
-                                               HostCmd_CMD_802_11_HS_CFG_ENH,
-                                               HostCmd_ACT_GEN_SET, 0,
-                                               &adapter->hs_cfg);
-                       else
-                               status = mwifiex_send_cmd_async(priv,
-                                               HostCmd_CMD_802_11_HS_CFG_ENH,
-                                               HostCmd_ACT_GEN_SET, 0,
-                                               &adapter->hs_cfg);
+
+                       status = mwifiex_send_cmd(priv,
+                                                 HostCmd_CMD_802_11_HS_CFG_ENH,
+                                                 HostCmd_ACT_GEN_SET, 0,
+                                                 &adapter->hs_cfg,
+                                                 cmd_type == MWIFIEX_SYNC_CMD);
+
                        if (hs_cfg->conditions == HS_CFG_CANCEL)
                                /* Restore previous condition */
                                adapter->hs_cfg.conditions =
@@ -586,8 +583,8 @@ int mwifiex_disable_auto_ds(struct mwifiex_private *priv)
 
        auto_ds.auto_ds = DEEP_SLEEP_OFF;
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
-                                    DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+                               DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true);
 }
 EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds);
 
@@ -601,8 +598,8 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate)
 {
        int ret;
 
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
-                                   HostCmd_ACT_GEN_GET, 0, NULL);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+                              HostCmd_ACT_GEN_GET, 0, NULL, true);
 
        if (!ret) {
                if (priv->is_data_rate_auto)
@@ -698,8 +695,8 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
                pg->power_max = (s8) dbm;
                pg->ht_bandwidth = HT_BW_40;
        }
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG,
-                                   HostCmd_ACT_GEN_SET, 0, buf);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_TXPWR_CFG,
+                              HostCmd_ACT_GEN_SET, 0, buf, true);
 
        kfree(buf);
        return ret;
@@ -722,12 +719,11 @@ int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)
        else
                adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
        sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
-                                   sub_cmd, BITMAP_STA_PS, NULL);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+                              sub_cmd, BITMAP_STA_PS, NULL, true);
        if ((!ret) && (sub_cmd == DIS_AUTO_PS))
-               ret = mwifiex_send_cmd_async(priv,
-                                            HostCmd_CMD_802_11_PS_MODE_ENH,
-                                            GET_PS, 0, NULL);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+                                      GET_PS, 0, NULL, false);
 
        return ret;
 }
@@ -851,9 +847,9 @@ static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,
                               struct mwifiex_ds_encrypt_key *encrypt_key)
 {
 
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
-                                    HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
-                                    encrypt_key);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+                               HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+                               encrypt_key, true);
 }
 
 /*
@@ -917,9 +913,8 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
                        enc_key = NULL;
 
                /* Send request to firmware */
-               ret = mwifiex_send_cmd_async(priv,
-                                            HostCmd_CMD_802_11_KEY_MATERIAL,
-                                            HostCmd_ACT_GEN_SET, 0, enc_key);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+                                      HostCmd_ACT_GEN_SET, 0, enc_key, false);
                if (ret)
                        return ret;
        }
@@ -929,9 +924,9 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
        else
                priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
 
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
-                                   HostCmd_ACT_GEN_SET, 0,
-                                   &priv->curr_pkt_filter);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+                              HostCmd_ACT_GEN_SET, 0,
+                              &priv->curr_pkt_filter, true);
 
        return ret;
 }
@@ -966,10 +961,9 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
                 */
                /* Send the key as PTK to firmware */
                encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
-               ret = mwifiex_send_cmd_async(priv,
-                                            HostCmd_CMD_802_11_KEY_MATERIAL,
-                                            HostCmd_ACT_GEN_SET,
-                                            KEY_INFO_ENABLED, encrypt_key);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+                                      HostCmd_ACT_GEN_SET,
+                                      KEY_INFO_ENABLED, encrypt_key, false);
                if (ret)
                        return ret;
 
@@ -993,15 +987,13 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
                encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
 
        if (remove_key)
-               ret = mwifiex_send_cmd_sync(priv,
-                                           HostCmd_CMD_802_11_KEY_MATERIAL,
-                                           HostCmd_ACT_GEN_SET,
-                                           !KEY_INFO_ENABLED, encrypt_key);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+                                      HostCmd_ACT_GEN_SET,
+                                      !KEY_INFO_ENABLED, encrypt_key, true);
        else
-               ret = mwifiex_send_cmd_sync(priv,
-                                           HostCmd_CMD_802_11_KEY_MATERIAL,
-                                           HostCmd_ACT_GEN_SET,
-                                           KEY_INFO_ENABLED, encrypt_key);
+               ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+                                      HostCmd_ACT_GEN_SET,
+                                      KEY_INFO_ENABLED, encrypt_key, true);
 
        return ret;
 }
@@ -1105,8 +1097,8 @@ mwifiex_get_ver_ext(struct mwifiex_private *priv)
        struct mwifiex_ver_ext ver_ext;
 
        memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext));
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT,
-                                 HostCmd_ACT_GEN_GET, 0, &ver_ext))
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,
+                            HostCmd_ACT_GEN_GET, 0, &ver_ext, true))
                return -1;
 
        return 0;
@@ -1131,8 +1123,8 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
                        ieee80211_frequency_to_channel(chan->center_freq);
                roc_cfg.duration = cpu_to_le32(duration);
        }
-       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_REMAIN_ON_CHAN,
-                                 action, 0, &roc_cfg)) {
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN,
+                            action, 0, &roc_cfg, true)) {
                dev_err(priv->adapter->dev, "failed to remain on channel\n");
                return -1;
        }
@@ -1164,8 +1156,8 @@ mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role)
                break;
        }
 
-       mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE,
-                             HostCmd_ACT_GEN_SET, 0, NULL);
+       mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+                        HostCmd_ACT_GEN_SET, 0, NULL, true);
 
        return mwifiex_sta_init_cmd(priv, false);
 }
@@ -1180,8 +1172,8 @@ int
 mwifiex_get_stats_info(struct mwifiex_private *priv,
                       struct mwifiex_ds_get_stats *log)
 {
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
-                                    HostCmd_ACT_GEN_GET, 0, log);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_GET_LOG,
+                               HostCmd_ACT_GEN_GET, 0, log, true);
 }
 
 /*
@@ -1223,8 +1215,7 @@ static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
                return -1;
        }
 
-       return mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw);
-
+       return mwifiex_send_cmd(priv, cmd_no, action, 0, reg_rw, true);
 }
 
 /*
@@ -1289,8 +1280,8 @@ mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
        rd_eeprom.byte_count = cpu_to_le16((u16) bytes);
 
        /* Send request to firmware */
-       ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
-                                   HostCmd_ACT_GEN_GET, 0, &rd_eeprom);
+       ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
+                              HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true);
 
        if (!ret)
                memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
index 5efd456af5715380c363106b1d2eee47ea77ffd0..8cec6e4ba8c4345d3518c8a407c19145beb48dc5 100644 (file)
@@ -180,7 +180,7 @@ static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv,
        memset(&vht_cap, 0, sizeof(struct ieee80211_vht_cap));
 
        mwifiex_fill_vht_cap_tlv(priv, &vht_cap, priv->curr_bss_params.band);
-       memcpy(pos, &vht_cap, sizeof(struct ieee80211_ht_cap));
+       memcpy(pos, &vht_cap, sizeof(vht_cap));
 
        return 0;
 }
@@ -864,8 +864,8 @@ mwifiex_tdls_process_config_link(struct mwifiex_private *priv, u8 *peer)
 
        memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
        tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK;
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER,
-                                    HostCmd_ACT_GEN_SET, 0, &tdls_oper);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
+                               HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
 }
 
 static int
@@ -891,8 +891,8 @@ mwifiex_tdls_process_create_link(struct mwifiex_private *priv, u8 *peer)
        mwifiex_hold_tdls_packets(priv, peer);
        memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
        tdls_oper.tdls_action = MWIFIEX_TDLS_CREATE_LINK;
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER,
-                                    HostCmd_ACT_GEN_SET, 0, &tdls_oper);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
+                               HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
 }
 
 static int
@@ -920,8 +920,8 @@ mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, u8 *peer)
        mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
        memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
        tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
-       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER,
-                                    HostCmd_ACT_GEN_SET, 0, &tdls_oper);
+       return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
+                               HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
 }
 
 static int
@@ -1033,8 +1033,8 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
                                             TDLS_LINK_TEARDOWN);
                memcpy(&tdls_oper.peer_mac, sta_ptr->mac_addr, ETH_ALEN);
                tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
-               if (mwifiex_send_cmd_async(priv, HostCmd_CMD_TDLS_OPER,
-                                          HostCmd_ACT_GEN_SET, 0, &tdls_oper))
+               if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
+                                    HostCmd_ACT_GEN_SET, 0, &tdls_oper, false))
                        dev_warn(priv->adapter->dev,
                                 "Disable link failed for TDLS peer %pM",
                                 sta_ptr->mac_addr);
index 64424c81b44f5bf55601e75a8a4d47e51b6bc9b9..a6a6a53cda40686bd0da8ba1bcdf32f100177723 100644 (file)
@@ -226,8 +226,8 @@ void mwifiex_set_vht_width(struct mwifiex_private *priv,
        if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80)
                vht_cfg.misc_config |= VHT_BW_80_160_80P80;
 
-       mwifiex_send_cmd_sync(priv, HostCmd_CMD_11AC_CFG,
-                             HostCmd_ACT_GEN_SET, 0, &vht_cfg);
+       mwifiex_send_cmd(priv, HostCmd_CMD_11AC_CFG,
+                        HostCmd_ACT_GEN_SET, 0, &vht_cfg, true);
 
        return;
 }
index 2d47ba70225c78e38356b33fa0a2f53e8a78d8f0..ae50e916d8f2da09f0f57f446dae80d1cbcf4982 100644 (file)
@@ -150,9 +150,9 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
        case EVENT_ADDBA:
                dev_dbg(adapter->dev, "event: ADDBA Request\n");
                if (priv->media_connected)
-                       mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
-                                              HostCmd_ACT_GEN_SET, 0,
-                                              adapter->event_body);
+                       mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
+                                        HostCmd_ACT_GEN_SET, 0,
+                                        adapter->event_body, false);
                break;
        case EVENT_DELBA:
                dev_dbg(adapter->dev, "event: DELBA Request\n");
index e8ebbd4bc3cd3348b271a6d930781cb799b97300..ae30c390ebd31c215674c842c2d9b03af57b93ee 100644 (file)
@@ -22,8 +22,6 @@
 
 #define USB_VERSION    "1.0"
 
-static const char usbdriver_name[] = "usb8xxx";
-
 static struct mwifiex_if_ops usb_ops;
 static struct semaphore add_remove_card_sem;
 static struct usb_card_rec *usb_card;
@@ -527,13 +525,6 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
                                                   MWIFIEX_BSS_ROLE_ANY),
                                  MWIFIEX_ASYNC_CMD);
 
-#ifdef CONFIG_PM
-       /* Resume handler may be called due to remote wakeup,
-        * force to exit suspend anyway
-        */
-       usb_disable_autosuspend(card->udev);
-#endif /* CONFIG_PM */
-
        return 0;
 }
 
@@ -567,13 +558,12 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
 }
 
 static struct usb_driver mwifiex_usb_driver = {
-       .name = usbdriver_name,
+       .name = "mwifiex_usb",
        .probe = mwifiex_usb_probe,
        .disconnect = mwifiex_usb_disconnect,
        .id_table = mwifiex_usb_table,
        .suspend = mwifiex_usb_suspend,
        .resume = mwifiex_usb_resume,
-       .supports_autosuspend = 1,
 };
 
 static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
@@ -776,11 +766,13 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
        switch (le16_to_cpu(card->udev->descriptor.idProduct)) {
        case USB8897_PID_1:
        case USB8897_PID_2:
+               adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
                strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME);
                break;
        case USB8797_PID_1:
        case USB8797_PID_2:
        default:
+               adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
                strcpy(adapter->fw_name, USB8797_DEFAULT_FW_NAME);
                break;
        }
@@ -1034,7 +1026,6 @@ static void mwifiex_usb_cleanup_module(void)
 
        if (usb_card && usb_card->adapter) {
                struct mwifiex_adapter *adapter = usb_card->adapter;
-               int i;
 
                /* In case driver is removed when asynchronous FW downloading is
                 * in progress
@@ -1045,11 +1036,8 @@ static void mwifiex_usb_cleanup_module(void)
                if (adapter->is_suspended)
                        mwifiex_usb_resume(usb_card->intf);
 #endif
-               for (i = 0; i < adapter->priv_num; i++)
-                       if ((GET_BSS_ROLE(adapter->priv[i]) ==
-                            MWIFIEX_BSS_ROLE_STA) &&
-                           adapter->priv[i]->media_connected)
-                               mwifiex_deauthenticate(adapter->priv[i], NULL);
+
+               mwifiex_deauthenticate_all(adapter);
 
                mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
                                                          MWIFIEX_BSS_ROLE_ANY),
index 8d37bfc578bdb595fc165b2144122b330aa2f041..c3824e37f3f24a30d951510a75cd4640346620d8 100644 (file)
@@ -72,7 +72,7 @@ int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
                return -1;
        }
 
-       return mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL);
+       return mwifiex_send_cmd(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL, true);
 }
 EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw);
 
@@ -104,6 +104,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
                info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
                info->is_hs_configured = adapter->is_hs_configured;
                info->hs_activated = adapter->hs_activated;
+               info->is_cmd_timedout = adapter->is_cmd_timedout;
                info->num_cmd_host_to_card_failure
                                = adapter->dbg.num_cmd_host_to_card_failure;
                info->num_cmd_sleep_cfm_host_to_card_failure
@@ -119,7 +120,6 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
                info->num_cmd_assoc_failure =
                                        adapter->dbg.num_cmd_assoc_failure;
                info->num_tx_timeout = adapter->dbg.num_tx_timeout;
-               info->num_cmd_timeout = adapter->dbg.num_cmd_timeout;
                info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
                info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
                memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
index e0ba0115e5aefcb79690559ee1b953ab58f52290..1c5f2b66f0578304f1613eb2df49cd6fe30f151d 100644 (file)
@@ -554,7 +554,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
        mwifiex_wmm_delete_all_ralist(priv);
        memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
 
-       if (priv->adapter->if_ops.clean_pcie_ring)
+       if (priv->adapter->if_ops.clean_pcie_ring &&
+           !priv->adapter->surprise_removed)
                priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
 
index 4987c3f942ce7dff2bb599feab7bb1aa26d40f50..3c0a0a86ba12038056dee4bbc37d12cb50ae9868 100644 (file)
@@ -81,6 +81,9 @@ MODULE_PARM_DESC(ap_mode_default,
  */
 
 #define        MWL8K_HW_TIMER_REGISTER                 0x0000a600
+#define BBU_RXRDY_CNT_REG                      0x0000a860
+#define NOK_CCA_CNT_REG                                0x0000a6a0
+#define BBU_AVG_NOISE_VAL                      0x67
 
 #define MWL8K_A2H_EVENTS       (MWL8K_A2H_INT_DUMMY | \
                                 MWL8K_A2H_INT_CHNL_SWITCHED | \
@@ -112,6 +115,8 @@ MODULE_PARM_DESC(ap_mode_default,
  */
 #define MWL8K_NUM_AMPDU_STREAMS        (TOTAL_HW_TX_QUEUES - 1)
 
+#define MWL8K_NUM_CHANS 18
+
 struct rxd_ops {
        int rxd_size;
        void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
@@ -289,6 +294,12 @@ struct mwl8k_priv {
 
        /* bitmap of running BSSes */
        u32 running_bsses;
+
+       /* ACS related */
+       bool sw_scan_start;
+       struct ieee80211_channel *acs_chan;
+       unsigned long channel_time;
+       struct survey_info survey[MWL8K_NUM_CHANS];
 };
 
 #define MAX_WEP_KEY_LEN         13
@@ -396,6 +407,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
 #define MWL8K_CMD_SET_HW_SPEC          0x0004
 #define MWL8K_CMD_MAC_MULTICAST_ADR    0x0010
 #define MWL8K_CMD_GET_STAT             0x0014
+#define MWL8K_CMD_BBP_REG_ACCESS       0x001a
 #define MWL8K_CMD_RADIO_CONTROL                0x001c
 #define MWL8K_CMD_RF_TX_POWER          0x001e
 #define MWL8K_CMD_TX_POWER             0x001f
@@ -2986,6 +2998,47 @@ static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw)
        return rc;
 }
 
+/*
+ * CMD_BBP_REG_ACCESS.
+ */
+struct mwl8k_cmd_bbp_reg_access {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __le16 offset;
+       u8 value;
+       u8 rsrv[3];
+} __packed;
+
+static int
+mwl8k_cmd_bbp_reg_access(struct ieee80211_hw *hw,
+                        u16 action,
+                        u16 offset,
+                        u8 *value)
+{
+       struct mwl8k_cmd_bbp_reg_access *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_BBP_REG_ACCESS);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le16(action);
+       cmd->offset = cpu_to_le16(offset);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+
+       if (!rc)
+               *value = cmd->value;
+       else
+               *value = 0;
+
+       kfree(cmd);
+
+       return rc;
+}
+
 /*
  * CMD_SET_POST_SCAN.
  */
@@ -3016,6 +3069,64 @@ mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac)
        return rc;
 }
 
+static int freq_to_idx(struct mwl8k_priv *priv, int freq)
+{
+       struct ieee80211_supported_band *sband;
+       int band, ch, idx = 0;
+
+       for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
+               sband = priv->hw->wiphy->bands[band];
+               if (!sband)
+                       continue;
+
+               for (ch = 0; ch < sband->n_channels; ch++, idx++)
+                       if (sband->channels[ch].center_freq == freq)
+                               goto exit;
+       }
+
+exit:
+       return idx;
+}
+
+static void mwl8k_update_survey(struct mwl8k_priv *priv,
+                               struct ieee80211_channel *channel)
+{
+       u32 cca_cnt, rx_rdy;
+       s8 nf = 0, idx;
+       struct survey_info *survey;
+
+       idx = freq_to_idx(priv, priv->acs_chan->center_freq);
+       if (idx >= MWL8K_NUM_CHANS) {
+               wiphy_err(priv->hw->wiphy, "Failed to update survey\n");
+               return;
+       }
+
+       survey = &priv->survey[idx];
+
+       cca_cnt = ioread32(priv->regs + NOK_CCA_CNT_REG);
+       cca_cnt /= 1000; /* uSecs to mSecs */
+       survey->channel_time_busy = (u64) cca_cnt;
+
+       rx_rdy = ioread32(priv->regs + BBU_RXRDY_CNT_REG);
+       rx_rdy /= 1000; /* uSecs to mSecs */
+       survey->channel_time_rx = (u64) rx_rdy;
+
+       priv->channel_time = jiffies - priv->channel_time;
+       survey->channel_time = jiffies_to_msecs(priv->channel_time);
+
+       survey->channel = channel;
+
+       mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &nf);
+
+       /* Make sure sign is negative else ACS  at hostapd fails */
+       survey->noise = nf * -1;
+
+       survey->filled = SURVEY_INFO_NOISE_DBM |
+                        SURVEY_INFO_CHANNEL_TIME |
+                        SURVEY_INFO_CHANNEL_TIME_BUSY |
+                        SURVEY_INFO_CHANNEL_TIME_RX;
+}
+
 /*
  * CMD_SET_RF_CHANNEL.
  */
@@ -3033,6 +3144,7 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
        enum nl80211_channel_type channel_type =
                cfg80211_get_chandef_type(&conf->chandef);
        struct mwl8k_cmd_set_rf_channel *cmd;
+       struct mwl8k_priv *priv = hw->priv;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -3049,13 +3161,29 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
        else if (channel->band == IEEE80211_BAND_5GHZ)
                cmd->channel_flags |= cpu_to_le32(0x00000004);
 
-       if (channel_type == NL80211_CHAN_NO_HT ||
-           channel_type == NL80211_CHAN_HT20)
+       if (!priv->sw_scan_start) {
+               if (channel_type == NL80211_CHAN_NO_HT ||
+                   channel_type == NL80211_CHAN_HT20)
+                       cmd->channel_flags |= cpu_to_le32(0x00000080);
+               else if (channel_type == NL80211_CHAN_HT40MINUS)
+                       cmd->channel_flags |= cpu_to_le32(0x000001900);
+               else if (channel_type == NL80211_CHAN_HT40PLUS)
+                       cmd->channel_flags |= cpu_to_le32(0x000000900);
+       } else {
                cmd->channel_flags |= cpu_to_le32(0x00000080);
-       else if (channel_type == NL80211_CHAN_HT40MINUS)
-               cmd->channel_flags |= cpu_to_le32(0x000001900);
-       else if (channel_type == NL80211_CHAN_HT40PLUS)
-               cmd->channel_flags |= cpu_to_le32(0x000000900);
+       }
+
+       if (priv->sw_scan_start) {
+               /* Store current channel stats
+                * before switching to newer one.
+                * This will be processed only for AP fw.
+                */
+               if (priv->channel_time != 0)
+                       mwl8k_update_survey(priv, priv->acs_chan);
+
+               priv->channel_time = jiffies;
+               priv->acs_chan =  channel;
+       }
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -5263,6 +5391,27 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
 {
        struct mwl8k_priv *priv = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_supported_band *sband;
+
+       if (priv->ap_fw) {
+               sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+
+               if (sband && idx >= sband->n_channels) {
+                       idx -= sband->n_channels;
+                       sband = NULL;
+               }
+
+               if (!sband)
+                       sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
+
+               if (!sband || idx >= sband->n_channels)
+                       return -ENOENT;
+
+               memcpy(survey, &priv->survey[idx], sizeof(*survey));
+               survey->channel = &sband->channels[idx];
+
+               return 0;
+       }
 
        if (idx != 0)
                return -ENOENT;
@@ -5406,6 +5555,40 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        return rc;
 }
 
+static void mwl8k_sw_scan_start(struct ieee80211_hw *hw)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       u8 tmp;
+
+       if (!priv->ap_fw)
+               return;
+
+       /* clear all stats */
+       priv->channel_time = 0;
+       ioread32(priv->regs + BBU_RXRDY_CNT_REG);
+       ioread32(priv->regs + NOK_CCA_CNT_REG);
+       mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &tmp);
+
+       priv->sw_scan_start = true;
+}
+
+static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       u8 tmp;
+
+       if (!priv->ap_fw)
+               return;
+
+       priv->sw_scan_start = false;
+
+       /* clear all stats */
+       priv->channel_time = 0;
+       ioread32(priv->regs + BBU_RXRDY_CNT_REG);
+       ioread32(priv->regs + NOK_CCA_CNT_REG);
+       mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &tmp);
+}
+
 static const struct ieee80211_ops mwl8k_ops = {
        .tx                     = mwl8k_tx,
        .start                  = mwl8k_start,
@@ -5424,6 +5607,8 @@ static const struct ieee80211_ops mwl8k_ops = {
        .get_stats              = mwl8k_get_stats,
        .get_survey             = mwl8k_get_survey,
        .ampdu_action           = mwl8k_ampdu_action,
+       .sw_scan_start          = mwl8k_sw_scan_start,
+       .sw_scan_complete       = mwl8k_sw_scan_complete,
 };
 
 static void mwl8k_finalize_join_worker(struct work_struct *work)
index d01edd2c50c505866cb554826659e24b4489c68f..a9e94b6db5b7e961d25ec2c58a2eb50d46bc621d 100644 (file)
@@ -59,7 +59,8 @@ int orinoco_wiphy_register(struct wiphy *wiphy)
        for (i = 0; i < NUM_CHANNELS; i++) {
                if (priv->channel_mask & (1 << i)) {
                        priv->channels[i].center_freq =
-                               ieee80211_dsss_chan_to_freq(i + 1);
+                               ieee80211_channel_to_frequency(i + 1,
+                                                          IEEE80211_BAND_2GHZ);
                        channels++;
                }
        }
@@ -177,7 +178,7 @@ static int orinoco_set_monitor_channel(struct wiphy *wiphy,
        if (chandef->chan->band != IEEE80211_BAND_2GHZ)
                return -EINVAL;
 
-       channel = ieee80211_freq_to_dsss_chan(chandef->chan->center_freq);
+       channel = ieee80211_frequency_to_channel(chandef->chan->center_freq);
 
        if ((channel < 1) || (channel > NUM_CHANNELS) ||
             !(priv->channel_mask & (1 << (channel - 1))))
index c09c8437c0b821072633c1022b348722d3913170..49300d04efdf0e7221a2b0f64f0475ad6f73ee59 100644 (file)
@@ -1193,7 +1193,7 @@ int orinoco_hw_get_freq(struct orinoco_private *priv)
                goto out;
 
        }
-       freq = ieee80211_dsss_chan_to_freq(channel);
+       freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
 
  out:
        orinoco_unlock(priv, &flags);
index e8c5714bfd11c24642933b824d299c165a768b27..e175b9b8561b594299d69d237624e3604932d22f 100644 (file)
@@ -110,7 +110,8 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
                break;
        }
 
-       freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel));
+       freq = ieee80211_channel_to_frequency(
+               le16_to_cpu(bss->a.channel), IEEE80211_BAND_2GHZ);
        channel = ieee80211_get_channel(wiphy, freq);
        if (!channel) {
                printk(KERN_DEBUG "Invalid channel designation %04X(%04X)",
@@ -146,7 +147,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
        ie_len = len - sizeof(*bss);
        ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len);
        chan = ie ? ie[2] : 0;
-       freq = ieee80211_dsss_chan_to_freq(chan);
+       freq = ieee80211_channel_to_frequency(chan, IEEE80211_BAND_2GHZ);
        channel = ieee80211_get_channel(wiphy, freq);
 
        timestamp = le64_to_cpu(bss->timestamp);
index 3b5508f982e80b8376d6bcb20c63dae6fd5586e0..b7a867b50b9476fb2c54ad9ccbb28815e6fa70e6 100644 (file)
@@ -444,7 +444,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
                for (i = 0; i < (6 - frq->e); i++)
                        denom *= 10;
 
-               chan = ieee80211_freq_to_dsss_chan(frq->m / denom);
+               chan = ieee80211_frequency_to_channel(frq->m / denom);
        }
 
        if ((chan < 1) || (chan > NUM_CHANNELS) ||
index 6e635cfa24c8dea70eb439f3724ee52adc01d27d..b7ab3dfb3de8a758e7d7636970ddfd87918feebd 100644 (file)
@@ -513,7 +513,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
        if (!buf)
                return -ENOMEM;
 
-       left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
+       left = block_size = min_t(size_t, P54U_FW_BLOCK, priv->fw->size);
        strcpy(buf, p54u_firmware_upload_3887);
        left -= strlen(p54u_firmware_upload_3887);
        tmp += strlen(p54u_firmware_upload_3887);
index 78fa64d3f2232a85a15a8b88f698765f80c9dfc8..ecbb0546cf3eed4b14f86c64a6d649d808c8eed3 100644 (file)
@@ -644,7 +644,7 @@ prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info,
        wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
        if (wpa_ie_len > 0) {
                iwe.cmd = IWEVGENIE;
-               iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
+               iwe.u.data.length = min_t(size_t, wpa_ie_len, MAX_WPA_IE_LEN);
                current_ev = iwe_stream_add_point(info, current_ev, end_buf,
                                                  &iwe, wpa_ie);
        }
index 2e89a865a67d1023d9ae64e0351c42d91c15c47e..39d22a154341019fe8038bdfa1f7e1b4cb560cf2 100644 (file)
@@ -1290,7 +1290,8 @@ static int set_channel(struct usbnet *usbdev, int channel)
        if (is_associated(usbdev))
                return 0;
 
-       dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000;
+       dsconfig = 1000 *
+               ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
 
        len = sizeof(config);
        ret = rndis_query_oid(usbdev,
index 14a90ddf585cde6169d35a0a5aa8631969aa10bf..a49c3d73ea2c9a21679e0dc52f746be2b1089c4a 100644 (file)
@@ -764,7 +764,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
        /*
         * Overwrite TX done handler
         */
-       PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
+       INIT_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
 
        return 0;
 }
index 2e3d1645e68bb68fb827070f126beaefb1b7e3c6..90fdb02b55e79debd5bd89b31104e90a260c596c 100644 (file)
@@ -286,7 +286,7 @@ static ssize_t rt2x00debug_read_queue_dump(struct file *file,
        if (retval)
                return retval;
 
-       status = min((size_t)skb->len, length);
+       status = min_t(size_t, skb->len, length);
        if (copy_to_user(buf, skb->data, status)) {
                status = -EFAULT;
                goto exit;
index 7980ab1f9eca3032a7af8b6c4993798895640c66..959e699702e85076245c85d1fb6ac578a7254e7a 100644 (file)
@@ -335,7 +335,18 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
        entry->flags2 = info->control.rates[1].idx >= 0 ?
                ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
        entry->retry_limit = info->control.rates[0].count;
+
+       /* We must be sure that tx_flags is written last because the HW
+        * looks at it to check if the rest of data is valid or not
+        */
+       wmb();
        entry->flags = cpu_to_le32(tx_flags);
+       /* We must be sure this has been written before followings HW
+        * register write, because this write will made the HW attempts
+        * to DMA the just-written data
+        */
+       wmb();
+
        __skb_queue_tail(&ring->queue, skb);
        if (ring->entries - skb_queue_len(&ring->queue) < 2)
                ieee80211_stop_queue(dev, prio);
@@ -476,13 +487,21 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev)
                struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE);
                dma_addr_t *mapping;
                entry = &priv->rx_ring[i];
-               if (!skb)
-                       return 0;
-
+               if (!skb) {
+                       wiphy_err(dev->wiphy, "Cannot allocate RX skb\n");
+                       return -ENOMEM;
+               }
                priv->rx_buf[i] = skb;
                mapping = (dma_addr_t *)skb->cb;
                *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb),
                                          MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+
+               if (pci_dma_mapping_error(priv->pdev, *mapping)) {
+                       kfree_skb(skb);
+                       wiphy_err(dev->wiphy, "Cannot map DMA for RX skb\n");
+                       return -ENOMEM;
+               }
+
                entry->rx_buf = cpu_to_le32(*mapping);
                entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
                                           MAX_RX_SIZE);
@@ -619,11 +638,23 @@ static int rtl8180_start(struct ieee80211_hw *dev)
 
        if (priv->r8185) {
                reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
+
+               /* CW is not on per-packet basis.
+                * in rtl8185 the CW_VALUE reg is used.
+                */
                reg &= ~RTL818X_CW_CONF_PERPACKET_CW;
+               /* retry limit IS on per-packet basis.
+                * the short and long retry limit in TX_CONF
+                * reg are ignored
+                */
                reg |= RTL818X_CW_CONF_PERPACKET_RETRY;
                rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
 
                reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
+               /* TX antenna and TX gain are not on per-packet basis.
+                * TX Antenna is selected by ANTSEL reg (RX in BB regs).
+                * TX gain is selected with CCK_TX_AGC and OFDM_TX_AGC regs
+                */
                reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN;
                reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL;
                reg |=  RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
@@ -642,6 +673,8 @@ static int rtl8180_start(struct ieee80211_hw *dev)
        else
                reg &= ~RTL818X_TX_CONF_HW_SEQNUM;
 
+       reg &= ~RTL818X_TX_CONF_DISCW;
+
        /* different meaning, same value on both rtl8185 and rtl8180 */
        reg &= ~RTL818X_TX_CONF_SAT_HWPLCP;
 
@@ -1135,7 +1168,7 @@ static int rtl8180_probe(struct pci_dev *pdev,
        return 0;
 
  err_iounmap:
-       iounmap(priv->map);
+       pci_iounmap(pdev, priv->map);
 
  err_free_dev:
        ieee80211_free_hw(dev);
index c2ffce7a907c90cf3fcc01400f50f2850d371533..bf3cf124e4eaac4e16fe9cbcd9299dbbcb9df250 100644 (file)
@@ -5,7 +5,7 @@ menuconfig RTL_CARDS
        ---help---
          This option will enable support for the Realtek mac80211-based
          wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de,
-         rtl8723eu, and rtl8188eu share some common code.
+         rtl8723ae, rtl8723be, and rtl8188ae share some common code.
 
 if RTL_CARDS
 
@@ -48,12 +48,27 @@ config RTL8723AE
        depends on PCI
        select RTLWIFI
        select RTLWIFI_PCI
+       select RTL8723_COMMON
+       select RTLBTCOEXIST
        ---help---
        This is the driver for Realtek RTL8723AE 802.11n PCIe
        wireless network adapters.
 
        If you choose to build it as a module, it will be called rtl8723ae
 
+config RTL8723BE
+       tristate "Realtek RTL8723BE PCIe Wireless Network Adapter"
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
+       select RTL8723_COMMON
+       select RTLBTCOEXIST
+       ---help---
+       This is the driver for Realtek RTL8723BE 802.11n PCIe
+       wireless network adapters.
+
+       If you choose to build it as a module, it will be called rtl8723be
+
 config RTL8188EE
        tristate "Realtek RTL8188EE Wireless Network Adapter"
        depends on PCI
@@ -101,4 +116,14 @@ config RTL8192C_COMMON
        depends on RTL8192CE || RTL8192CU
        default y
 
+config RTL8723_COMMON
+       tristate
+       depends on RTL8723AE || RTL8723BE
+       default y
+
+config RTLBTCOEXIST
+       tristate
+       depends on RTL8723AE || RTL8723BE
+       default y
+
 endif
index d56f023a4b90dfadabf45670b2f5c8d0ca1fa46d..bba36a06abcc4c3cf3d896eab771ef0406611993 100644 (file)
@@ -24,6 +24,9 @@ obj-$(CONFIG_RTL8192CU)               += rtl8192cu/
 obj-$(CONFIG_RTL8192SE)                += rtl8192se/
 obj-$(CONFIG_RTL8192DE)                += rtl8192de/
 obj-$(CONFIG_RTL8723AE)                += rtl8723ae/
+obj-$(CONFIG_RTL8723BE)                += rtl8723be/
 obj-$(CONFIG_RTL8188EE)                += rtl8188ee/
+obj-$(CONFIG_RTLBTCOEXIST)     += btcoexist/
+obj-$(CONFIG_RTL8723_COMMON)   += rtl8723com/
 
 ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/Makefile b/drivers/net/wireless/rtlwifi/btcoexist/Makefile
new file mode 100644 (file)
index 0000000..47ceecf
--- /dev/null
@@ -0,0 +1,7 @@
+btcoexist-objs :=      halbtc8723b2ant.o       \
+                       halbtcoutsrc.o          \
+                       rtl_btc.o
+
+obj-$(CONFIG_RTLBTCOEXIST) += btcoexist.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
new file mode 100644 (file)
index 0000000..d76684e
--- /dev/null
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ******************************************************************************/
+
+#ifndef        __HALBT_PRECOMP_H__
+#define __HALBT_PRECOMP_H__
+/*************************************************************
+ * include files
+ *************************************************************/
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+
+#include "halbtcoutsrc.h"
+
+#include "halbtc8723b2ant.h"
+
+#define BIT0   0x00000001
+#define BIT1   0x00000002
+#define BIT2   0x00000004
+#define BIT3   0x00000008
+#define BIT4   0x00000010
+#define BIT5   0x00000020
+#define BIT6   0x00000040
+#define BIT7   0x00000080
+#define BIT8   0x00000100
+#define BIT9   0x00000200
+#define BIT10  0x00000400
+#define BIT11  0x00000800
+#define BIT12  0x00001000
+#define BIT13  0x00002000
+#define BIT14  0x00004000
+#define BIT15  0x00008000
+#define BIT16  0x00010000
+#define BIT17  0x00020000
+#define BIT18  0x00040000
+#define BIT19  0x00080000
+#define BIT20  0x00100000
+#define BIT21  0x00200000
+#define BIT22  0x00400000
+#define BIT23  0x00800000
+#define BIT24  0x01000000
+#define BIT25  0x02000000
+#define BIT26  0x04000000
+#define BIT27  0x08000000
+#define BIT28  0x10000000
+#define BIT29  0x20000000
+#define BIT30  0x40000000
+#define BIT31  0x80000000
+
+#endif /* __HALBT_PRECOMP_H__ */
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
new file mode 100644 (file)
index 0000000..d916ab9
--- /dev/null
@@ -0,0 +1,3698 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/***************************************************************
+ * Description:
+ *
+ * This file is for RTL8723B Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ **************************************************************/
+/**************************************************************
+ * include files
+ **************************************************************/
+#include "halbt_precomp.h"
+/**************************************************************
+ * Global variables, these are static variables
+ **************************************************************/
+static struct coex_dm_8723b_2ant glcoex_dm_8723b_2ant;
+static struct coex_dm_8723b_2ant *coex_dm = &glcoex_dm_8723b_2ant;
+static struct coex_sta_8723b_2ant glcoex_sta_8723b_2ant;
+static struct coex_sta_8723b_2ant *coex_sta = &glcoex_sta_8723b_2ant;
+
+static const char *const glbt_info_src_8723b_2ant[] = {
+       "BT Info[wifi fw]",
+       "BT Info[bt rsp]",
+       "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8723b_2ant = 20130731;
+static u32 glcoex_ver_8723b_2ant = 0x3b;
+
+/**************************************************************
+ * local function proto type if needed
+ **************************************************************/
+/**************************************************************
+ * local function start with btc8723b2ant_
+ **************************************************************/
+static u8 btc8723b2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+                                    u8 rssi_thresh1)
+{
+       s32 bt_rssi = 0;
+       u8 bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+       bt_rssi = coex_sta->bt_rssi;
+
+       if (level_num == 2) {
+               if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+                   (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+                       if (bt_rssi >= rssi_thresh +
+                                      BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+                               bt_rssi_state = BTC_RSSI_STATE_HIGH;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "switch to High\n");
+                       } else {
+                               bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "stay at Low\n");
+                       }
+               } else {
+                       if (bt_rssi < rssi_thresh) {
+                               bt_rssi_state = BTC_RSSI_STATE_LOW;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "switch to Low\n");
+                       } else {
+                               bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "stay at High\n");
+                       }
+               }
+       } else if (level_num == 3) {
+               if (rssi_thresh > rssi_thresh1) {
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                 "[BTCoex], BT Rssi thresh error!!\n");
+                       return coex_sta->pre_bt_rssi_state;
+               }
+
+               if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+                   (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+                       if (bt_rssi >= rssi_thresh +
+                                      BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+                               bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "switch to Medium\n");
+                       } else {
+                               bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "stay at Low\n");
+                       }
+               } else if ((coex_sta->pre_bt_rssi_state ==
+                                               BTC_RSSI_STATE_MEDIUM) ||
+                          (coex_sta->pre_bt_rssi_state ==
+                                               BTC_RSSI_STATE_STAY_MEDIUM)) {
+                       if (bt_rssi >= rssi_thresh1 +
+                                      BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+                               bt_rssi_state = BTC_RSSI_STATE_HIGH;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "switch to High\n");
+                       } else if (bt_rssi < rssi_thresh) {
+                               bt_rssi_state = BTC_RSSI_STATE_LOW;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "switch to Low\n");
+                       } else {
+                               bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "stay at Medium\n");
+                       }
+               } else {
+                       if (bt_rssi < rssi_thresh1) {
+                               bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "switch to Medium\n");
+                       } else {
+                               bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+                                         "[BTCoex], BT Rssi state "
+                                         "stay at High\n");
+                       }
+               }
+       }
+
+       coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+       return bt_rssi_state;
+}
+
+static u8 btc8723b2ant_wifi_rssi_state(struct btc_coexist *btcoexist,
+                                      u8 index, u8 level_num,
+                                      u8 rssi_thresh, u8 rssi_thresh1)
+{
+       s32 wifi_rssi = 0;
+       u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+       btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+       if (level_num == 2) {
+               if ((coex_sta->pre_wifi_rssi_state[index] ==
+                                               BTC_RSSI_STATE_LOW) ||
+                   (coex_sta->pre_wifi_rssi_state[index] ==
+                                               BTC_RSSI_STATE_STAY_LOW)) {
+                       if (wifi_rssi >= rssi_thresh +
+                                        BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+                               wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "switch to High\n");
+                       } else {
+                               wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "stay at Low\n");
+                       }
+               } else {
+                       if (wifi_rssi < rssi_thresh) {
+                               wifi_rssi_state = BTC_RSSI_STATE_LOW;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "switch to Low\n");
+                       } else {
+                               wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "stay at High\n");
+                       }
+               }
+       } else if (level_num == 3) {
+               if (rssi_thresh > rssi_thresh1) {
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+                                 "[BTCoex], wifi RSSI thresh error!!\n");
+                       return coex_sta->pre_wifi_rssi_state[index];
+               }
+
+               if ((coex_sta->pre_wifi_rssi_state[index] ==
+                                               BTC_RSSI_STATE_LOW) ||
+                   (coex_sta->pre_wifi_rssi_state[index] ==
+                                               BTC_RSSI_STATE_STAY_LOW)) {
+                       if (wifi_rssi >= rssi_thresh +
+                                       BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+                               wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "switch to Medium\n");
+                       } else {
+                               wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "stay at Low\n");
+                       }
+               } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+                                               BTC_RSSI_STATE_MEDIUM) ||
+                          (coex_sta->pre_wifi_rssi_state[index] ==
+                                               BTC_RSSI_STATE_STAY_MEDIUM)) {
+                       if (wifi_rssi >= rssi_thresh1 +
+                                        BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) {
+                               wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "switch to High\n");
+                       } else if (wifi_rssi < rssi_thresh) {
+                               wifi_rssi_state = BTC_RSSI_STATE_LOW;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "switch to Low\n");
+                       } else {
+                               wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "stay at Medium\n");
+                       }
+               } else {
+                       if (wifi_rssi < rssi_thresh1) {
+                               wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "switch to Medium\n");
+                       } else {
+                               wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_WIFI_RSSI_STATE,
+                                         "[BTCoex], wifi RSSI state "
+                                         "stay at High\n");
+                       }
+               }
+       }
+
+       coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+       return wifi_rssi_state;
+}
+
+static void btc8723b2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+       u32 reg_hp_txrx, reg_lp_txrx, u32tmp;
+       u32 reg_hp_tx = 0, reg_hp_rx = 0;
+       u32 reg_lp_tx = 0, reg_lp_rx = 0;
+
+       reg_hp_txrx = 0x770;
+       reg_lp_txrx = 0x774;
+
+       u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+       reg_hp_tx = u32tmp & MASKLWORD;
+       reg_hp_rx = (u32tmp & MASKHWORD) >> 16;
+
+       u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+       reg_lp_tx = u32tmp & MASKLWORD;
+       reg_lp_rx = (u32tmp & MASKHWORD) >> 16;
+
+       coex_sta->high_priority_tx = reg_hp_tx;
+       coex_sta->high_priority_rx = reg_hp_rx;
+       coex_sta->low_priority_tx = reg_lp_tx;
+       coex_sta->low_priority_rx = reg_lp_rx;
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+                 "[BTCoex], High Priority Tx/Rx(reg 0x%x)=0x%x(%d)/0x%x(%d)\n",
+                 reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx);
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+                 "[BTCoex], Low Priority Tx/Rx(reg 0x%x)=0x%x(%d)/0x%x(%d)\n",
+                 reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx);
+
+       /* reset counter */
+       btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static bool btc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
+{
+       static bool pre_wifi_busy;
+       static bool pre_under_4way;
+       static bool pre_bt_hs_on;
+       bool wifi_busy = false, under_4way = false, bt_hs_on = false;
+       bool wifi_connected = false;
+
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+                          &wifi_connected);
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+                          &under_4way);
+
+       if (wifi_connected) {
+               if (wifi_busy != pre_wifi_busy) {
+                       pre_wifi_busy = wifi_busy;
+                       return true;
+               }
+
+               if (under_4way != pre_under_4way) {
+                       pre_under_4way = under_4way;
+                       return true;
+               }
+
+               if (bt_hs_on != pre_bt_hs_on) {
+                       pre_bt_hs_on = bt_hs_on;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static void btc8723b2ant_update_bt_link_info(struct btc_coexist *btcoexist)
+{
+       /*struct btc_stack_info *stack_info = &btcoexist->stack_info;*/
+       struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+       bool bt_hs_on = false;
+
+#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) /* profile from bt patch */
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+       bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+       bt_link_info->sco_exist = coex_sta->sco_exist;
+       bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+       bt_link_info->pan_exist = coex_sta->pan_exist;
+       bt_link_info->hid_exist = coex_sta->hid_exist;
+
+       /* work around for HS mode. */
+       if (bt_hs_on) {
+               bt_link_info->pan_exist = true;
+               bt_link_info->bt_link_exist = true;
+       }
+#else  /* profile from bt stack */
+       bt_link_info->bt_link_exist = stack_info->bt_link_exist;
+       bt_link_info->sco_exist = stack_info->sco_exist;
+       bt_link_info->a2dp_exist = stack_info->a2dp_exist;
+       bt_link_info->pan_exist = stack_info->pan_exist;
+       bt_link_info->hid_exist = stack_info->hid_exist;
+
+       /*for win-8 stack HID report error*/
+       if (!stack_info->hid_exist)
+               stack_info->hid_exist = coex_sta->hid_exist;
+       /*sync  BTInfo with BT firmware and stack*/
+       /* when stack HID report error, here we use the info from bt fw.*/
+       if (!stack_info->bt_link_exist)
+               stack_info->bt_link_exist = coex_sta->bt_link_exist;
+#endif
+       /* check if Sco only */
+       if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+           !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+               bt_link_info->sco_only = true;
+       else
+               bt_link_info->sco_only = false;
+
+       /* check if A2dp only */
+       if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist &&
+           !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+               bt_link_info->a2dp_only = true;
+       else
+               bt_link_info->a2dp_only = false;
+
+       /* check if Pan only */
+       if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+           bt_link_info->pan_exist && !bt_link_info->hid_exist)
+               bt_link_info->pan_only = true;
+       else
+               bt_link_info->pan_only = false;
+
+       /* check if Hid only */
+       if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+           !bt_link_info->pan_exist && bt_link_info->hid_exist)
+               bt_link_info->hid_only = true;
+       else
+               bt_link_info->hid_only = false;
+}
+
+static u8 btc8723b2ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+       struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+       bool bt_hs_on = false;
+       u8 algorithm = BT_8723B_2ANT_COEX_ALGO_UNDEFINED;
+       u8 num_of_diff_profile = 0;
+
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+       if (!bt_link_info->bt_link_exist) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], No BT link exists!!!\n");
+               return algorithm;
+       }
+
+       if (bt_link_info->sco_exist)
+               num_of_diff_profile++;
+       if (bt_link_info->hid_exist)
+               num_of_diff_profile++;
+       if (bt_link_info->pan_exist)
+               num_of_diff_profile++;
+       if (bt_link_info->a2dp_exist)
+               num_of_diff_profile++;
+
+       if (num_of_diff_profile == 1) {
+               if (bt_link_info->sco_exist) {
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], SCO only\n");
+                       algorithm = BT_8723B_2ANT_COEX_ALGO_SCO;
+               } else {
+                       if (bt_link_info->hid_exist) {
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                         "[BTCoex], HID only\n");
+                               algorithm = BT_8723B_2ANT_COEX_ALGO_HID;
+                       } else if (bt_link_info->a2dp_exist) {
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                         "[BTCoex], A2DP only\n");
+                               algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP;
+                       } else if (bt_link_info->pan_exist) {
+                               if (bt_hs_on) {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], PAN(HS) only\n");
+                                       algorithm =
+                                               BT_8723B_2ANT_COEX_ALGO_PANHS;
+                               } else {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], PAN(EDR) only\n");
+                                       algorithm =
+                                               BT_8723B_2ANT_COEX_ALGO_PANEDR;
+                               }
+                       }
+               }
+       } else if (num_of_diff_profile == 2) {
+               if (bt_link_info->sco_exist) {
+                       if (bt_link_info->hid_exist) {
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                         "[BTCoex], SCO + HID\n");
+                               algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                       } else if (bt_link_info->a2dp_exist) {
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                         "[BTCoex], SCO + A2DP ==> SCO\n");
+                               algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                       } else if (bt_link_info->pan_exist) {
+                               if (bt_hs_on) {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], SCO + PAN(HS)\n");
+                                       algorithm = BT_8723B_2ANT_COEX_ALGO_SCO;
+                               } else {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], SCO + PAN(EDR)\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                               }
+                       }
+               } else {
+                       if (bt_link_info->hid_exist &&
+                           bt_link_info->a2dp_exist) {
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                         "[BTCoex], HID + A2DP\n");
+                               algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP;
+                       } else if (bt_link_info->hid_exist &&
+                                  bt_link_info->pan_exist) {
+                               if (bt_hs_on) {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], HID + PAN(HS)\n");
+                                       algorithm = BT_8723B_2ANT_COEX_ALGO_HID;
+                               } else {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], HID + PAN(EDR)\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                               }
+                       } else if (bt_link_info->pan_exist &&
+                                  bt_link_info->a2dp_exist) {
+                               if (bt_hs_on) {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], A2DP + PAN(HS)\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS;
+                               } else {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex],A2DP + PAN(EDR)\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP;
+                               }
+                       }
+               }
+       } else if (num_of_diff_profile == 3) {
+               if (bt_link_info->sco_exist) {
+                       if (bt_link_info->hid_exist &&
+                           bt_link_info->a2dp_exist) {
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                         "[BTCoex], SCO + HID + A2DP"
+                                         " ==> HID\n");
+                               algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                       } else if (bt_link_info->hid_exist &&
+                                  bt_link_info->pan_exist) {
+                               if (bt_hs_on) {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], SCO + HID + "
+                                                 "PAN(HS)\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                               } else {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], SCO + HID + "
+                                                 "PAN(EDR)\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                               }
+                       } else if (bt_link_info->pan_exist &&
+                                  bt_link_info->a2dp_exist) {
+                               if (bt_hs_on) {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], SCO + A2DP + "
+                                                 "PAN(HS)\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                               } else {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], SCO + A2DP + "
+                                                 "PAN(EDR) ==> HID\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                               }
+                       }
+               } else {
+                       if (bt_link_info->hid_exist &&
+                           bt_link_info->pan_exist &&
+                           bt_link_info->a2dp_exist) {
+                               if (bt_hs_on) {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], HID + A2DP + "
+                                                 "PAN(HS)\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_HID_A2DP;
+                               } else {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], HID + A2DP + "
+                                                 "PAN(EDR)\n");
+                                       algorithm =
+                                       BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+                               }
+                       }
+               }
+       } else if (num_of_diff_profile >= 3) {
+               if (bt_link_info->sco_exist) {
+                       if (bt_link_info->hid_exist &&
+                           bt_link_info->pan_exist &&
+                           bt_link_info->a2dp_exist) {
+                               if (bt_hs_on) {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], Error!!! SCO + HID"
+                                                 " + A2DP + PAN(HS)\n");
+                               } else {
+                                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                                 "[BTCoex], SCO + HID + A2DP +"
+                                                 " PAN(EDR)==>PAN(EDR)+HID\n");
+                                       algorithm =
+                                           BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
+                               }
+                       }
+               }
+       }
+       return algorithm;
+}
+
+static bool btc8723b_need_dec_pwr(struct btc_coexist *btcoexist)
+{
+       bool ret = false;
+       bool bt_hs_on = false, wifi_connected = false;
+       s32 bt_hs_rssi = 0;
+       u8 bt_rssi_state;
+
+       if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on))
+               return false;
+       if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+                               &wifi_connected))
+               return false;
+       if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi))
+               return false;
+
+       bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+       if (wifi_connected) {
+               if (bt_hs_on) {
+                       if (bt_hs_rssi > 37) {
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+                                         "[BTCoex], Need to decrease bt "
+                                         "power for HS mode!!\n");
+                               ret = true;
+                       }
+               } else {
+                       if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                           (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+                                         "[BTCoex], Need to decrease bt "
+                                         "power for Wifi is connected!!\n");
+                               ret = true;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static void btc8723b2ant_set_fw_dac_swing_level(struct btc_coexist *btcoexist,
+                                               u8 dac_swing_lvl)
+{
+       u8 h2c_parameter[1] = {0};
+
+       /* There are several type of dacswing
+        * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6
+        */
+       h2c_parameter[0] = dac_swing_lvl;
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+                 "[BTCoex], Set Dac Swing Level=0x%x\n", dac_swing_lvl);
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+                 "[BTCoex], FW write 0x64=0x%x\n", h2c_parameter[0]);
+
+       btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter);
+}
+
+static void btc8723b2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist,
+                                          bool dec_bt_pwr)
+{
+       u8 h2c_parameter[1] = {0};
+
+       h2c_parameter[0] = 0;
+
+       if (dec_bt_pwr)
+               h2c_parameter[0] |= BIT1;
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+                 "[BTCoex], decrease Bt Power : %s, FW write 0x62=0x%x\n",
+                 (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]);
+
+       btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter);
+}
+
+static void btc8723b2ant_dec_bt_pwr(struct btc_coexist *btcoexist,
+                                   bool force_exec, bool dec_bt_pwr)
+{
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+                 "[BTCoex], %s Dec BT power = %s\n",
+                 (force_exec ? "force to" : ""), (dec_bt_pwr ? "ON" : "OFF"));
+       coex_dm->cur_dec_bt_pwr = dec_bt_pwr;
+
+       if (!force_exec) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], bPreDecBtPwr=%d, bCurDecBtPwr=%d\n",
+                         coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr);
+
+               if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr)
+                       return;
+       }
+       btc8723b2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr);
+
+       coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr;
+}
+
+static void btc8723b2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist,
+                                         bool force_exec, u8 fw_dac_swing_lvl)
+{
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+                 "[BTCoex], %s set FW Dac Swing level = %d\n",
+                 (force_exec ? "force to" : ""), fw_dac_swing_lvl);
+       coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl;
+
+       if (!force_exec) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], preFwDacSwingLvl=%d, "
+                         "curFwDacSwingLvl=%d\n",
+                         coex_dm->pre_fw_dac_swing_lvl,
+                         coex_dm->cur_fw_dac_swing_lvl);
+
+               if (coex_dm->pre_fw_dac_swing_lvl ==
+                  coex_dm->cur_fw_dac_swing_lvl)
+                       return;
+       }
+
+       btc8723b2ant_set_fw_dac_swing_level(btcoexist,
+                                           coex_dm->cur_fw_dac_swing_lvl);
+       coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl;
+}
+
+static void btc8723b2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist,
+                                                bool rx_rf_shrink_on)
+{
+       if (rx_rf_shrink_on) {
+               /* Shrink RF Rx LPF corner */
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                         "[BTCoex], Shrink RF Rx LPF corner!!\n");
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+                                         0xfffff, 0xffffc);
+       } else {
+               /* Resume RF Rx LPF corner */
+               /* After initialized, we can use coex_dm->btRf0x1eBackup */
+               if (btcoexist->initilized) {
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                                 "[BTCoex], Resume RF Rx LPF corner!!\n");
+                       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+                                                 0xfffff,
+                                                 coex_dm->bt_rf0x1e_backup);
+               }
+       }
+}
+
+static void btc8723b2ant_rf_shrink(struct btc_coexist *btcoexist,
+                                  bool force_exec, bool rx_rf_shrink_on)
+{
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+                 "[BTCoex], %s turn Rx RF Shrink = %s\n",
+                 (force_exec ? "force to" : ""), (rx_rf_shrink_on ?
+                 "ON" : "OFF"));
+       coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on;
+
+       if (!force_exec) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+                         "[BTCoex], bPreRfRxLpfShrink=%d, "
+                         "bCurRfRxLpfShrink=%d\n",
+                         coex_dm->pre_rf_rx_lpf_shrink,
+                         coex_dm->cur_rf_rx_lpf_shrink);
+
+               if (coex_dm->pre_rf_rx_lpf_shrink ==
+                   coex_dm->cur_rf_rx_lpf_shrink)
+                       return;
+       }
+       btc8723b2ant_set_sw_rf_rx_lpf_corner(btcoexist,
+                                            coex_dm->cur_rf_rx_lpf_shrink);
+
+       coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink;
+}
+
+static void btc8723b_set_penalty_txrate(struct btc_coexist *btcoexist,
+                                       bool low_penalty_ra)
+{
+       u8 h2c_parameter[6] = {0};
+
+       h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty*/
+
+       if (low_penalty_ra) {
+               h2c_parameter[1] |= BIT0;
+               /*normal rate except MCS7/6/5, OFDM54/48/36*/
+               h2c_parameter[2] = 0x00;
+               h2c_parameter[3] = 0xf7;  /*MCS7 or OFDM54*/
+               h2c_parameter[4] = 0xf8;  /*MCS6 or OFDM48*/
+               h2c_parameter[5] = 0xf9;  /*MCS5 or OFDM36*/
+       }
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+                 "[BTCoex], set WiFi Low-Penalty Retry: %s",
+                 (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+       btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void btc8723b2ant_low_penalty_ra(struct btc_coexist *btcoexist,
+                                       bool force_exec, bool low_penalty_ra)
+{
+       /*return; */
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+                 "[BTCoex], %s turn LowPenaltyRA = %s\n",
+                 (force_exec ? "force to" : ""), (low_penalty_ra ?
+                 "ON" : "OFF"));
+       coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+       if (!force_exec) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+                         "[BTCoex], bPreLowPenaltyRa=%d, "
+                         "bCurLowPenaltyRa=%d\n",
+                         coex_dm->pre_low_penalty_ra,
+                         coex_dm->cur_low_penalty_ra);
+
+               if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+                       return;
+       }
+       btc8723b_set_penalty_txrate(btcoexist, coex_dm->cur_low_penalty_ra);
+
+       coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void btc8723b2ant_set_dac_swing_reg(struct btc_coexist *btcoexist,
+                                          u32 level)
+{
+       u8 val = (u8) level;
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                 "[BTCoex], Write SwDacSwing = 0x%x\n", level);
+       btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val);
+}
+
+static void btc8723b2ant_set_sw_fulltime_dac_swing(struct btc_coexist *btcoex,
+                                                  bool sw_dac_swing_on,
+                                                  u32 sw_dac_swing_lvl)
+{
+       if (sw_dac_swing_on)
+               btc8723b2ant_set_dac_swing_reg(btcoex, sw_dac_swing_lvl);
+       else
+               btc8723b2ant_set_dac_swing_reg(btcoex, 0x18);
+}
+
+
+static void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist,
+                                  bool force_exec, bool dac_swing_on,
+                                  u32 dac_swing_lvl)
+{
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+                 "[BTCoex], %s turn DacSwing=%s, dac_swing_lvl=0x%x\n",
+                 (force_exec ? "force to" : ""),
+                 (dac_swing_on ? "ON" : "OFF"), dac_swing_lvl);
+       coex_dm->cur_dac_swing_on = dac_swing_on;
+       coex_dm->cur_dac_swing_lvl = dac_swing_lvl;
+
+       if (!force_exec) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+                         "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x,"
+                         " bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n",
+                         coex_dm->pre_dac_swing_on, coex_dm->pre_dac_swing_lvl,
+                         coex_dm->cur_dac_swing_on,
+                         coex_dm->cur_dac_swing_lvl);
+
+               if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) &&
+                   (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl))
+                       return;
+       }
+       mdelay(30);
+       btc8723b2ant_set_sw_fulltime_dac_swing(btcoexist, dac_swing_on,
+                                              dac_swing_lvl);
+
+       coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on;
+       coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl;
+}
+
+static void btc8723b2ant_set_agc_table(struct btc_coexist *btcoexist,
+                                      bool agc_table_en)
+{
+       u8 rssi_adjust_val = 0;
+
+       /*  BB AGC Gain Table */
+       if (agc_table_en) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                         "[BTCoex], BB Agc Table On!\n");
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6e1A0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6d1B0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6c1C0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6b1D0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6a1E0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x691F0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x68200001);
+       } else {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                         "[BTCoex], BB Agc Table Off!\n");
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001);
+               btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001);
+       }
+
+
+       /* RF Gain */
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000);
+       if (agc_table_en) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                         "[BTCoex], Agc Table On!\n");
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b,
+                                         0xfffff, 0x38fff);
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b,
+                                         0xfffff, 0x38ffe);
+       } else {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                         "[BTCoex], Agc Table Off!\n");
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b,
+                                         0xfffff, 0x380c3);
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b,
+                                         0xfffff, 0x28ce6);
+       }
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x1);
+
+       if (agc_table_en) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                         "[BTCoex], Agc Table On!\n");
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40,
+                                         0xfffff, 0x38fff);
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40,
+                                         0xfffff, 0x38ffe);
+       } else {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                         "[BTCoex], Agc Table Off!\n");
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40,
+                                         0xfffff, 0x380c3);
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40,
+                                         0xfffff, 0x28ce6);
+       }
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x0);
+
+       /* set rssiAdjustVal for wifi module. */
+       if (agc_table_en)
+               rssi_adjust_val = 8;
+       btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON,
+                          &rssi_adjust_val);
+}
+
+static void btc8723b2ant_agc_table(struct btc_coexist *btcoexist,
+                                  bool force_exec, bool agc_table_en)
+{
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+                 "[BTCoex], %s %s Agc Table\n",
+                 (force_exec ? "force to" : ""),
+                 (agc_table_en ? "Enable" : "Disable"));
+       coex_dm->cur_agc_table_en = agc_table_en;
+
+       if (!force_exec) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+                         "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n",
+                         coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en);
+
+               if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en)
+                       return;
+       }
+       btc8723b2ant_set_agc_table(btcoexist, agc_table_en);
+
+       coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en;
+}
+
+static void btc8723b2ant_set_coex_table(struct btc_coexist *btcoexist,
+                                       u32 val0x6c0, u32 val0x6c4,
+                                       u32 val0x6c8, u8 val0x6cc)
+{
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                 "[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0);
+       btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                 "[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4);
+       btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                 "[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8);
+       btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+                 "[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc);
+       btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void btc8723b2ant_coex_table(struct btc_coexist *btcoexist,
+                                   bool force_exec, u32 val0x6c0,
+                                   u32 val0x6c4, u32 val0x6c8,
+                                   u8 val0x6cc)
+{
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+                 "[BTCoex], %s write Coex Table 0x6c0=0x%x,"
+                 " 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n",
+                 (force_exec ? "force to" : ""), val0x6c0,
+                 val0x6c4, val0x6c8, val0x6cc);
+       coex_dm->cur_val0x6c0 = val0x6c0;
+       coex_dm->cur_val0x6c4 = val0x6c4;
+       coex_dm->cur_val0x6c8 = val0x6c8;
+       coex_dm->cur_val0x6cc = val0x6cc;
+
+       if (!force_exec) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+                         "[BTCoex], preVal0x6c0=0x%x, "
+                         "preVal0x6c4=0x%x, preVal0x6c8=0x%x, "
+                         "preVal0x6cc=0x%x !!\n",
+                         coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4,
+                         coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc);
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+                         "[BTCoex], curVal0x6c0=0x%x, "
+                         "curVal0x6c4=0x%x, curVal0x6c8=0x%x, "
+                         "curVal0x6cc=0x%x !!\n",
+                         coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4,
+                         coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc);
+
+               if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+                   (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+                   (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+                   (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+                       return;
+       }
+       btc8723b2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+                                   val0x6c8, val0x6cc);
+
+       coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+       coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+       coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+       coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void btc8723b_coex_tbl_type(struct btc_coexist *btcoexist,
+                                  bool force_exec, u8 type)
+{
+       switch (type) {
+       case 0:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555,
+                                       0x55555555, 0xffff, 0x3);
+               break;
+       case 1:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555,
+                                       0x5afa5afa, 0xffff, 0x3);
+               break;
+       case 2:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+                                       0x5a5a5a5a, 0xffff, 0x3);
+               break;
+       case 3:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa,
+                                       0xaaaaaaaa, 0xffff, 0x3);
+               break;
+       case 4:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0xffffffff,
+                                       0xffffffff, 0xffff, 0x3);
+               break;
+       case 5:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x5fff5fff,
+                                       0x5fff5fff, 0xffff, 0x3);
+               break;
+       case 6:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+                                       0x5a5a5a5a, 0xffff, 0x3);
+               break;
+       case 7:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+                                       0x5afa5afa, 0xffff, 0x3);
+               break;
+       case 8:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x5aea5aea,
+                                       0x5aea5aea, 0xffff, 0x3);
+               break;
+       case 9:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+                                       0x5aea5aea, 0xffff, 0x3);
+               break;
+       case 10:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+                                       0x5aff5aff, 0xffff, 0x3);
+               break;
+       case 11:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+                                       0x5a5f5a5f, 0xffff, 0x3);
+               break;
+       case 12:
+               btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+                                       0x5f5f5f5f, 0xffff, 0x3);
+               break;
+       default:
+               break;
+       }
+}
+
+static void btc8723b2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist,
+                                               bool enable)
+{
+       u8 h2c_parameter[1] = {0};
+
+       if (enable)
+               h2c_parameter[0] |= BIT0;/* function enable*/
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+                 "[BTCoex], set FW for BT Ignore Wlan_Act, "
+                 "FW write 0x63=0x%x\n", h2c_parameter[0]);
+
+       btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void btc8723b2ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+                                        bool force_exec, bool enable)
+{
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+                 "[BTCoex], %s turn Ignore WlanAct %s\n",
+                 (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+       coex_dm->cur_ignore_wlan_act = enable;
+
+       if (!force_exec) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], bPreIgnoreWlanAct = %d, "
+                         "bCurIgnoreWlanAct = %d!!\n",
+                         coex_dm->pre_ignore_wlan_act,
+                         coex_dm->cur_ignore_wlan_act);
+
+               if (coex_dm->pre_ignore_wlan_act ==
+                   coex_dm->cur_ignore_wlan_act)
+                       return;
+       }
+       btc8723b2ant_set_fw_ignore_wlan_act(btcoexist, enable);
+
+       coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void btc8723b2ant_set_fw_ps_tdma(struct btc_coexist *btcoexist, u8 byte1,
+                                       u8 byte2, u8 byte3, u8 byte4, u8 byte5)
+{
+       u8 h2c_parameter[5];
+
+       h2c_parameter[0] = byte1;
+       h2c_parameter[1] = byte2;
+       h2c_parameter[2] = byte3;
+       h2c_parameter[3] = byte4;
+       h2c_parameter[4] = byte5;
+
+       coex_dm->ps_tdma_para[0] = byte1;
+       coex_dm->ps_tdma_para[1] = byte2;
+       coex_dm->ps_tdma_para[2] = byte3;
+       coex_dm->ps_tdma_para[3] = byte4;
+       coex_dm->ps_tdma_para[4] = byte5;
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+                 "[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n",
+                 h2c_parameter[0],
+                 h2c_parameter[1] << 24 | h2c_parameter[2] << 16 |
+                 h2c_parameter[3] << 8 | h2c_parameter[4]);
+
+       btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void btc8723b2ant_sw_mechanism1(struct btc_coexist *btcoexist,
+                                      bool shrink_rx_lpf, bool low_penalty_ra,
+                                      bool limited_dig, bool bt_lna_constrain)
+{
+       btc8723b2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf);
+       btc8723b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra);
+}
+
+static void btc8723b2ant_sw_mechanism2(struct btc_coexist *btcoexist,
+                                      bool agc_table_shift, bool adc_backoff,
+                                      bool sw_dac_swing, u32 dac_swing_lvl)
+{
+       btc8723b2ant_agc_table(btcoexist, NORMAL_EXEC, agc_table_shift);
+       btc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing,
+                              dac_swing_lvl);
+}
+
+static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec,
+                            bool turn_on, u8 type)
+{
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+                 "[BTCoex], %s turn %s PS TDMA, type=%d\n",
+                 (force_exec ? "force to" : ""),
+                 (turn_on ? "ON" : "OFF"), type);
+       coex_dm->cur_ps_tdma_on = turn_on;
+       coex_dm->cur_ps_tdma = type;
+
+       if (!force_exec) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n",
+                         coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on);
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n",
+                         coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma);
+
+               if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+                   (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+                       return;
+       }
+       if (turn_on) {
+               switch (type) {
+               case 1:
+               default:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+                                                   0x1a, 0xe1, 0x90);
+                       break;
+               case 2:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12,
+                                                   0x12, 0xe1, 0x90);
+                       break;
+               case 3:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c,
+                                                   0x3, 0xf1, 0x90);
+                       break;
+               case 4:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x10,
+                                                   0x03, 0xf1, 0x90);
+                       break;
+               case 5:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+                                                   0x1a, 0x60, 0x90);
+                       break;
+               case 6:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12,
+                                                   0x12, 0x60, 0x90);
+                       break;
+               case 7:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c,
+                                                   0x3, 0x70, 0x90);
+                       break;
+               case 8:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x10,
+                                                   0x3, 0x70, 0x90);
+                       break;
+               case 9:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+                                                   0x1a, 0xe1, 0x90);
+                       break;
+               case 10:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12,
+                                                   0x12, 0xe1, 0x90);
+                       break;
+               case 11:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+                                                   0xa, 0xe1, 0x90);
+                       break;
+               case 12:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5,
+                                                   0x5, 0xe1, 0x90);
+                       break;
+               case 13:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+                                                   0x1a, 0x60, 0x90);
+                       break;
+               case 14:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12,
+                                                   0x12, 0x60, 0x90);
+                       break;
+               case 15:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+                                                   0xa, 0x60, 0x90);
+                       break;
+               case 16:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5,
+                                                   0x5, 0x60, 0x90);
+                       break;
+               case 17:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x2f,
+                                                   0x2f, 0x60, 0x90);
+                       break;
+               case 18:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5,
+                                                   0x5, 0xe1, 0x90);
+                       break;
+               case 19:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+                                                   0x25, 0xe1, 0x90);
+                       break;
+               case 20:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+                                                   0x25, 0x60, 0x90);
+                       break;
+               case 21:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15,
+                                                   0x03, 0x70, 0x90);
+                       break;
+               case 71:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a,
+                                                   0x1a, 0xe1, 0x90);
+                       break;
+               }
+       } else {
+               /* disable PS tdma */
+               switch (type) {
+               case 0:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0,
+                                                   0x40, 0x0);
+                       break;
+               case 1:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0,
+                                                   0x48, 0x0);
+                       break;
+               default:
+                       btc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0,
+                                                   0x40, 0x0);
+                       break;
+               }
+       }
+
+       /* update pre state */
+       coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+       coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static void btc8723b2ant_coex_alloff(struct btc_coexist *btcoexist)
+{
+       /* fw all off */
+       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+       btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       /* sw all off */
+       btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false);
+       btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18);
+
+       /* hw all off */
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+       /* force to reset coex mechanism*/
+
+       btc8723b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6);
+       btc8723b2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false);
+
+       btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false);
+       btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18);
+}
+
+static void btc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+       bool wifi_connected = false;
+       bool low_pwr_disable = true;
+
+       btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+                          &low_pwr_disable);
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+                          &wifi_connected);
+
+       if (wifi_connected) {
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+       } else {
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+       }
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6);
+       btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false);
+       btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18);
+
+       coex_dm->need_recover_0x948 = true;
+       coex_dm->backup_0x948 = btcoexist->btc_read_2byte(btcoexist, 0x948);
+
+       btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+}
+
+static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist)
+{
+       bool common = false, wifi_connected = false;
+       bool wifi_busy = false;
+       bool bt_hs_on = false, low_pwr_disable = false;
+
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+                          &wifi_connected);
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+       if (!wifi_connected) {
+               low_pwr_disable = false;
+               btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+                                  &low_pwr_disable);
+
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], Wifi non-connected idle!!\n");
+
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff,
+                                         0x0);
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+               btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+               btc8723b2ant_sw_mechanism1(btcoexist, false, false, false,
+                                          false);
+               btc8723b2ant_sw_mechanism2(btcoexist, false, false, false,
+                                          0x18);
+
+               common = true;
+       } else {
+               if (BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+                   coex_dm->bt_status) {
+                       low_pwr_disable = false;
+                       btcoexist->btc_set(btcoexist,
+                                          BTC_SET_ACT_DISABLE_LOW_POWER,
+                                          &low_pwr_disable);
+
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Wifi connected + "
+                                 "BT non connected-idle!!\n");
+
+                       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1,
+                                                 0xfffff, 0x0);
+                       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+                       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC,
+                                                     0xb);
+                       btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+                                               false);
+
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+
+                       common = true;
+               } else if (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE ==
+                          coex_dm->bt_status) {
+                       low_pwr_disable = true;
+                       btcoexist->btc_set(btcoexist,
+                                          BTC_SET_ACT_DISABLE_LOW_POWER,
+                                          &low_pwr_disable);
+
+                       if (bt_hs_on)
+                               return false;
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Wifi connected + "
+                                 "BT connected-idle!!\n");
+
+                       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1,
+                                                 0xfffff, 0x0);
+                       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+                       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC,
+                                                     0xb);
+                       btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+                                               false);
+
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+
+                       common = true;
+               } else {
+                       low_pwr_disable = true;
+                       btcoexist->btc_set(btcoexist,
+                                          BTC_SET_ACT_DISABLE_LOW_POWER,
+                                          &low_pwr_disable);
+
+                       if (wifi_busy) {
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                         "[BTCoex], Wifi Connected-Busy + "
+                                         "BT Busy!!\n");
+                               common = false;
+                       } else {
+                               if (bt_hs_on)
+                                       return false;
+
+                               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                         "[BTCoex], Wifi Connected-Idle + "
+                                         "BT Busy!!\n");
+
+                               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A,
+                                                         0x1, 0xfffff, 0x0);
+                               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC,
+                                                      7);
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 21);
+                               btc8723b2ant_fw_dac_swing_lvl(btcoexist,
+                                                             NORMAL_EXEC,
+                                                             0xb);
+                               if (btc8723b_need_dec_pwr(btcoexist))
+                                       btc8723b2ant_dec_bt_pwr(btcoexist,
+                                                               NORMAL_EXEC,
+                                                               true);
+                               else
+                                       btc8723b2ant_dec_bt_pwr(btcoexist,
+                                                               NORMAL_EXEC,
+                                                               false);
+                               btc8723b2ant_sw_mechanism1(btcoexist, false,
+                                                          false, false,
+                                                          false);
+                               btc8723b2ant_sw_mechanism2(btcoexist, false,
+                                                          false, false,
+                                                          0x18);
+                               common = true;
+                       }
+               }
+       }
+
+       return common;
+}
+
+static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause,
+                         s32 result)
+{
+       /* Set PS TDMA for max interval == 1 */
+       if (tx_pause) {
+               BTC_PRINT(BTC_MSG_ALGORITHM,
+                         ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], TxPause = 1\n");
+
+               if (coex_dm->cur_ps_tdma == 71) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                            true, 5);
+                       coex_dm->tdma_adj_type = 5;
+               } else if (coex_dm->cur_ps_tdma == 1) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                            true, 5);
+                       coex_dm->tdma_adj_type = 5;
+               } else if (coex_dm->cur_ps_tdma == 2) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                            true, 6);
+                       coex_dm->tdma_adj_type = 6;
+               } else if (coex_dm->cur_ps_tdma == 3) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                            true, 7);
+                       coex_dm->tdma_adj_type = 7;
+               } else if (coex_dm->cur_ps_tdma == 4) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                            true, 8);
+                       coex_dm->tdma_adj_type = 8;
+               } else if (coex_dm->cur_ps_tdma == 9) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                            true, 13);
+                       coex_dm->tdma_adj_type = 13;
+               } else if (coex_dm->cur_ps_tdma == 10) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                            true, 14);
+                       coex_dm->tdma_adj_type = 14;
+               } else if (coex_dm->cur_ps_tdma == 11) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                            true, 15);
+                       coex_dm->tdma_adj_type = 15;
+               } else if (coex_dm->cur_ps_tdma == 12) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                            true, 16);
+                       coex_dm->tdma_adj_type = 16;
+               }
+
+               if (result == -1) {
+                       if (coex_dm->cur_ps_tdma == 5) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 6);
+                               coex_dm->tdma_adj_type = 6;
+                       } else if (coex_dm->cur_ps_tdma == 6) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 7);
+                               coex_dm->tdma_adj_type = 7;
+                       } else if (coex_dm->cur_ps_tdma == 7) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 8);
+                               coex_dm->tdma_adj_type = 8;
+                       } else if (coex_dm->cur_ps_tdma == 13) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 14);
+                               coex_dm->tdma_adj_type = 14;
+                       } else if (coex_dm->cur_ps_tdma == 14) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 15);
+                               coex_dm->tdma_adj_type = 15;
+                       } else if (coex_dm->cur_ps_tdma == 15) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 16);
+                               coex_dm->tdma_adj_type = 16;
+                       }
+               }  else if (result == 1) {
+                       if (coex_dm->cur_ps_tdma == 8) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 7);
+                               coex_dm->tdma_adj_type = 7;
+                       } else if (coex_dm->cur_ps_tdma == 7) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 6);
+                               coex_dm->tdma_adj_type = 6;
+                       } else if (coex_dm->cur_ps_tdma == 6) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 5);
+                               coex_dm->tdma_adj_type = 5;
+                       } else if (coex_dm->cur_ps_tdma == 16) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 15);
+                               coex_dm->tdma_adj_type = 15;
+                       } else if (coex_dm->cur_ps_tdma == 15) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 14);
+                               coex_dm->tdma_adj_type = 14;
+                       } else if (coex_dm->cur_ps_tdma == 14) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 13);
+                               coex_dm->tdma_adj_type = 13;
+                       }
+               }
+       } else {
+               BTC_PRINT(BTC_MSG_ALGORITHM,
+                         ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], TxPause = 0\n");
+               if (coex_dm->cur_ps_tdma == 5) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 71);
+                       coex_dm->tdma_adj_type = 71;
+               } else if (coex_dm->cur_ps_tdma == 6) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+                       coex_dm->tdma_adj_type = 2;
+               } else if (coex_dm->cur_ps_tdma == 7) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+                       coex_dm->tdma_adj_type = 3;
+               } else if (coex_dm->cur_ps_tdma == 8) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
+                       coex_dm->tdma_adj_type = 4;
+               } else if (coex_dm->cur_ps_tdma == 13) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+                       coex_dm->tdma_adj_type = 9;
+               } else if (coex_dm->cur_ps_tdma == 14) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+                       coex_dm->tdma_adj_type = 10;
+               } else if (coex_dm->cur_ps_tdma == 15) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+                       coex_dm->tdma_adj_type = 11;
+               } else if (coex_dm->cur_ps_tdma == 16) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12);
+                       coex_dm->tdma_adj_type = 12;
+               }
+
+               if (result == -1) {
+                       if (coex_dm->cur_ps_tdma == 71) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 1);
+                               coex_dm->tdma_adj_type = 1;
+                       } else if (coex_dm->cur_ps_tdma == 1) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 2);
+                               coex_dm->tdma_adj_type = 2;
+                       } else if (coex_dm->cur_ps_tdma == 2) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 3);
+                               coex_dm->tdma_adj_type = 3;
+                       } else if (coex_dm->cur_ps_tdma == 3) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 4);
+                               coex_dm->tdma_adj_type = 4;
+                       } else if (coex_dm->cur_ps_tdma == 9) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 10);
+                               coex_dm->tdma_adj_type = 10;
+                       } else if (coex_dm->cur_ps_tdma == 10) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 11);
+                               coex_dm->tdma_adj_type = 11;
+                       } else if (coex_dm->cur_ps_tdma == 11) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 12);
+                               coex_dm->tdma_adj_type = 12;
+                       }
+               }  else if (result == 1) {
+                       int tmp = coex_dm->cur_ps_tdma;
+                       switch (tmp) {
+                       case 4:
+                       case 3:
+                       case 2:
+                       case 12:
+                       case 11:
+                       case 10:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, tmp - 1);
+                               coex_dm->tdma_adj_type = tmp - 1;
+                               break;
+                       case 1:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 71);
+                               coex_dm->tdma_adj_type = 71;
+                               break;
+                       }
+               }
+       }
+}
+
+static void set_tdma_int2(struct btc_coexist *btcoexist, bool tx_pause,
+                         s32 result)
+{
+       /* Set PS TDMA for max interval == 2 */
+       if (tx_pause) {
+               BTC_PRINT(BTC_MSG_ALGORITHM,
+                         ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], TxPause = 1\n");
+               if (coex_dm->cur_ps_tdma == 1) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6);
+                       coex_dm->tdma_adj_type = 6;
+               } else if (coex_dm->cur_ps_tdma == 2) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6);
+                       coex_dm->tdma_adj_type = 6;
+               } else if (coex_dm->cur_ps_tdma == 3) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7);
+                       coex_dm->tdma_adj_type = 7;
+               } else if (coex_dm->cur_ps_tdma == 4) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
+                       coex_dm->tdma_adj_type = 8;
+               } else if (coex_dm->cur_ps_tdma == 9) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+                       coex_dm->tdma_adj_type = 14;
+               } else if (coex_dm->cur_ps_tdma == 10) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+                       coex_dm->tdma_adj_type = 14;
+               } else if (coex_dm->cur_ps_tdma == 11) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
+                       coex_dm->tdma_adj_type = 15;
+               } else if (coex_dm->cur_ps_tdma == 12) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16);
+                       coex_dm->tdma_adj_type = 16;
+               }
+               if (result == -1) {
+                       if (coex_dm->cur_ps_tdma == 5) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 6);
+                               coex_dm->tdma_adj_type = 6;
+                       } else if (coex_dm->cur_ps_tdma == 6) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 7);
+                               coex_dm->tdma_adj_type = 7;
+                       } else if (coex_dm->cur_ps_tdma == 7) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 8);
+                               coex_dm->tdma_adj_type = 8;
+                       } else if (coex_dm->cur_ps_tdma == 13) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 14);
+                               coex_dm->tdma_adj_type = 14;
+                       } else if (coex_dm->cur_ps_tdma == 14) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 15);
+                               coex_dm->tdma_adj_type = 15;
+                       } else if (coex_dm->cur_ps_tdma == 15) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 16);
+                               coex_dm->tdma_adj_type = 16;
+                       }
+               }  else if (result == 1) {
+                       if (coex_dm->cur_ps_tdma == 8) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 7);
+                               coex_dm->tdma_adj_type = 7;
+                       } else if (coex_dm->cur_ps_tdma == 7) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 6);
+                               coex_dm->tdma_adj_type = 6;
+                       } else if (coex_dm->cur_ps_tdma == 6) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 6);
+                               coex_dm->tdma_adj_type = 6;
+                       } else if (coex_dm->cur_ps_tdma == 16) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 15);
+                               coex_dm->tdma_adj_type = 15;
+                       } else if (coex_dm->cur_ps_tdma == 15) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 14);
+                               coex_dm->tdma_adj_type = 14;
+                       } else if (coex_dm->cur_ps_tdma == 14) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 14);
+                               coex_dm->tdma_adj_type = 14;
+                       }
+               }
+       } else {
+               BTC_PRINT(BTC_MSG_ALGORITHM,
+                         ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], TxPause = 0\n");
+               if (coex_dm->cur_ps_tdma == 5) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+                       coex_dm->tdma_adj_type = 2;
+               } else if (coex_dm->cur_ps_tdma == 6) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+                       coex_dm->tdma_adj_type = 2;
+               } else if (coex_dm->cur_ps_tdma == 7) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+                       coex_dm->tdma_adj_type = 3;
+               } else if (coex_dm->cur_ps_tdma == 8) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
+                       coex_dm->tdma_adj_type = 4;
+               } else if (coex_dm->cur_ps_tdma == 13) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+                       coex_dm->tdma_adj_type = 10;
+               } else if (coex_dm->cur_ps_tdma == 14) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+                       coex_dm->tdma_adj_type = 10;
+               } else if (coex_dm->cur_ps_tdma == 15) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+                       coex_dm->tdma_adj_type = 11;
+               } else if (coex_dm->cur_ps_tdma == 16) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12);
+                       coex_dm->tdma_adj_type = 12;
+               }
+               if (result == -1) {
+                       if (coex_dm->cur_ps_tdma == 1) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 2);
+                               coex_dm->tdma_adj_type = 2;
+                       } else if (coex_dm->cur_ps_tdma == 2) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 3);
+                               coex_dm->tdma_adj_type = 3;
+                       } else if (coex_dm->cur_ps_tdma == 3) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 4);
+                               coex_dm->tdma_adj_type = 4;
+                       } else if (coex_dm->cur_ps_tdma == 9) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 10);
+                               coex_dm->tdma_adj_type = 10;
+                       } else if (coex_dm->cur_ps_tdma == 10) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 11);
+                               coex_dm->tdma_adj_type = 11;
+                       } else if (coex_dm->cur_ps_tdma == 11) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 12);
+                               coex_dm->tdma_adj_type = 12;
+                       }
+               } else if (result == 1) {
+                       if (coex_dm->cur_ps_tdma == 4) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 3);
+                               coex_dm->tdma_adj_type = 3;
+                       } else if (coex_dm->cur_ps_tdma == 3) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 2);
+                               coex_dm->tdma_adj_type = 2;
+                       } else if (coex_dm->cur_ps_tdma == 2) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 2);
+                               coex_dm->tdma_adj_type = 2;
+                       } else if (coex_dm->cur_ps_tdma == 12) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 11);
+                               coex_dm->tdma_adj_type = 11;
+                       } else if (coex_dm->cur_ps_tdma == 11) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 10);
+                               coex_dm->tdma_adj_type = 10;
+                       } else if (coex_dm->cur_ps_tdma == 10) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 10);
+                               coex_dm->tdma_adj_type = 10;
+                       }
+               }
+       }
+}
+
+static void set_tdma_int3(struct btc_coexist *btcoexist, bool tx_pause,
+                         s32 result)
+{
+       /* Set PS TDMA for max interval == 3 */
+       if (tx_pause) {
+               BTC_PRINT(BTC_MSG_ALGORITHM,
+                         ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], TxPause = 1\n");
+               if (coex_dm->cur_ps_tdma == 1) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7);
+                       coex_dm->tdma_adj_type = 7;
+               } else if (coex_dm->cur_ps_tdma == 2) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7);
+                       coex_dm->tdma_adj_type = 7;
+               } else if (coex_dm->cur_ps_tdma == 3) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7);
+                       coex_dm->tdma_adj_type = 7;
+               } else if (coex_dm->cur_ps_tdma == 4) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
+                       coex_dm->tdma_adj_type = 8;
+               } else if (coex_dm->cur_ps_tdma == 9) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
+                       coex_dm->tdma_adj_type = 15;
+               } else if (coex_dm->cur_ps_tdma == 10) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
+                       coex_dm->tdma_adj_type = 15;
+               } else if (coex_dm->cur_ps_tdma == 11) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
+                       coex_dm->tdma_adj_type = 15;
+               } else if (coex_dm->cur_ps_tdma == 12) {
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16);
+                       coex_dm->tdma_adj_type = 16;
+               }
+               if (result == -1) {
+                       if (coex_dm->cur_ps_tdma == 5) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 7);
+                               coex_dm->tdma_adj_type = 7;
+                       } else if (coex_dm->cur_ps_tdma == 6) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 7);
+                               coex_dm->tdma_adj_type = 7;
+                       } else if (coex_dm->cur_ps_tdma == 7) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 8);
+                               coex_dm->tdma_adj_type = 8;
+                       } else if (coex_dm->cur_ps_tdma == 13) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 15);
+                               coex_dm->tdma_adj_type = 15;
+                       } else if (coex_dm->cur_ps_tdma == 14) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 15);
+                               coex_dm->tdma_adj_type = 15;
+                       } else if (coex_dm->cur_ps_tdma == 15) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 16);
+                               coex_dm->tdma_adj_type = 16;
+                       }
+               }  else if (result == 1) {
+                       if (coex_dm->cur_ps_tdma == 8) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 7);
+                               coex_dm->tdma_adj_type = 7;
+                       } else if (coex_dm->cur_ps_tdma == 7) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 7);
+                               coex_dm->tdma_adj_type = 7;
+                       } else if (coex_dm->cur_ps_tdma == 6) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 7);
+                               coex_dm->tdma_adj_type = 7;
+                       } else if (coex_dm->cur_ps_tdma == 16) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 15);
+                               coex_dm->tdma_adj_type = 15;
+                       } else if (coex_dm->cur_ps_tdma == 15) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 15);
+                               coex_dm->tdma_adj_type = 15;
+                       } else if (coex_dm->cur_ps_tdma == 14) {
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 15);
+                               coex_dm->tdma_adj_type = 15;
+                       }
+               }
+       } else {
+               BTC_PRINT(BTC_MSG_ALGORITHM,
+                         ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], TxPause = 0\n");
+               switch (coex_dm->cur_ps_tdma) {
+               case 5:
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+                       coex_dm->tdma_adj_type = 3;
+                       break;
+               case 6:
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+                       coex_dm->tdma_adj_type = 3;
+                       break;
+               case 7:
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+                       coex_dm->tdma_adj_type = 3;
+                       break;
+               case 8:
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
+                       coex_dm->tdma_adj_type = 4;
+                       break;
+               case 13:
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+                       coex_dm->tdma_adj_type = 11;
+                       break;
+               case 14:
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+                       coex_dm->tdma_adj_type = 11;
+                       break;
+               case 15:
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+                       coex_dm->tdma_adj_type = 11;
+                       break;
+               case 16:
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12);
+                       coex_dm->tdma_adj_type = 12;
+                       break;
+               }
+               if (result == -1) {
+                       switch (coex_dm->cur_ps_tdma) {
+                       case 1:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 3);
+                               coex_dm->tdma_adj_type = 3;
+                               break;
+                       case 2:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 3);
+                               coex_dm->tdma_adj_type = 3;
+                               break;
+                       case 3:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 4);
+                               coex_dm->tdma_adj_type = 4;
+                               break;
+                       case 9:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 11);
+                               coex_dm->tdma_adj_type = 11;
+                               break;
+                       case 10:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 11);
+                               coex_dm->tdma_adj_type = 11;
+                               break;
+                       case 11:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 12);
+                               coex_dm->tdma_adj_type = 12;
+                               break;
+                       }
+               } else if (result == 1) {
+                       switch (coex_dm->cur_ps_tdma) {
+                       case 4:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 3);
+                               coex_dm->tdma_adj_type = 3;
+                               break;
+                       case 3:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 3);
+                               coex_dm->tdma_adj_type = 3;
+                               break;
+                       case 2:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 3);
+                               coex_dm->tdma_adj_type = 3;
+                               break;
+                       case 12:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 11);
+                               coex_dm->tdma_adj_type = 11;
+                               break;
+                       case 11:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 11);
+                               coex_dm->tdma_adj_type = 11;
+                               break;
+                       case 10:
+                               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+                                                    true, 11);
+                               coex_dm->tdma_adj_type = 11;
+                       }
+               }
+       }
+}
+
+static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
+                                         bool sco_hid, bool tx_pause,
+                                         u8 max_interval)
+{
+       static s32 up, dn, m, n, wait_count;
+       /*0: no change, +1: increase WiFi duration, -1: decrease WiFi duration*/
+       s32 result;
+       u8 retry_count = 0;
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+                 "[BTCoex], TdmaDurationAdjust()\n");
+
+       if (!coex_dm->auto_tdma_adjust) {
+               coex_dm->auto_tdma_adjust = true;
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], first run TdmaDurationAdjust()!!\n");
+               if (sco_hid) {
+                       if (tx_pause) {
+                               if (max_interval == 1) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 13);
+                                       coex_dm->tdma_adj_type = 13;
+                               } else if (max_interval == 2) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 14);
+                                       coex_dm->tdma_adj_type = 14;
+                               } else if (max_interval == 3) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 15);
+                                       coex_dm->tdma_adj_type = 15;
+                               } else {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 15);
+                                       coex_dm->tdma_adj_type = 15;
+                               }
+                       } else {
+                               if (max_interval == 1) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 9);
+                                       coex_dm->tdma_adj_type = 9;
+                               } else if (max_interval == 2) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 10);
+                                       coex_dm->tdma_adj_type = 10;
+                               } else if (max_interval == 3) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 11);
+                                       coex_dm->tdma_adj_type = 11;
+                               } else {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 11);
+                                       coex_dm->tdma_adj_type = 11;
+                               }
+                       }
+               } else {
+                       if (tx_pause) {
+                               if (max_interval == 1) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 5);
+                                       coex_dm->tdma_adj_type = 5;
+                               } else if (max_interval == 2) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 6);
+                                       coex_dm->tdma_adj_type = 6;
+                               } else if (max_interval == 3) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 7);
+                                       coex_dm->tdma_adj_type = 7;
+                               } else {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 7);
+                                       coex_dm->tdma_adj_type = 7;
+                               }
+                       } else {
+                               if (max_interval == 1) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 1);
+                                       coex_dm->tdma_adj_type = 1;
+                               } else if (max_interval == 2) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 2);
+                                       coex_dm->tdma_adj_type = 2;
+                               } else if (max_interval == 3) {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 3);
+                                       coex_dm->tdma_adj_type = 3;
+                               } else {
+                                       btc8723b2ant_ps_tdma(btcoexist,
+                                                            NORMAL_EXEC,
+                                                            true, 3);
+                                       coex_dm->tdma_adj_type = 3;
+                               }
+                       }
+               }
+
+               up = 0;
+               dn = 0;
+               m = 1;
+               n = 3;
+               result = 0;
+               wait_count = 0;
+       } else {
+               /*accquire the BT TRx retry count from BT_Info byte2*/
+               retry_count = coex_sta->bt_retry_cnt;
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], retry_count = %d\n", retry_count);
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_count=%d\n",
+                         up, dn, m, n, wait_count);
+               result = 0;
+               wait_count++;
+                /* no retry in the last 2-second duration*/
+               if (retry_count == 0) {
+                       up++;
+                       dn--;
+
+                       if (dn <= 0)
+                               dn = 0;
+
+                       if (up >= n) {
+                               wait_count = 0;
+                               n = 3;
+                               up = 0;
+                               dn = 0;
+                               result = 1;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_TRACE_FW_DETAIL,
+                                         "[BTCoex], Increase wifi "
+                                         "duration!!\n");
+                       } /* <=3 retry in the last 2-second duration*/
+               } else if (retry_count <= 3) {
+                       up--;
+                       dn++;
+
+                       if (up <= 0)
+                               up = 0;
+
+                       if (dn == 2) {
+                               if (wait_count <= 2)
+                                       m++;
+                               else
+                                       m = 1;
+
+                               if (m >= 20)
+                                       m = 20;
+
+                               n = 3 * m;
+                               up = 0;
+                               dn = 0;
+                               wait_count = 0;
+                               result = -1;
+                               BTC_PRINT(BTC_MSG_ALGORITHM,
+                                         ALGO_TRACE_FW_DETAIL,
+                                         "[BTCoex], Decrease wifi duration "
+                                         "for retry_counter<3!!\n");
+                       }
+               } else {
+                       if (wait_count == 1)
+                               m++;
+                       else
+                               m = 1;
+
+                       if (m >= 20)
+                               m = 20;
+
+                       n = 3 * m;
+                       up = 0;
+                       dn = 0;
+                       wait_count = 0;
+                       result = -1;
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                                 "[BTCoex], Decrease wifi duration "
+                                 "for retry_counter>3!!\n");
+               }
+
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], max Interval = %d\n", max_interval);
+               if (max_interval == 1)
+                       set_tdma_int1(btcoexist, tx_pause, result);
+               else if (max_interval == 2)
+                       set_tdma_int2(btcoexist, tx_pause, result);
+               else if (max_interval == 3)
+                       set_tdma_int3(btcoexist, tx_pause, result);
+       }
+
+       /*if current PsTdma not match with the recorded one (when scan, dhcp..),
+        *then we have to adjust it back to the previous recorded one.
+        */
+       if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) {
+               bool scan = false, link = false, roam = false;
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                         "[BTCoex], PsTdma type dismatch!!!, "
+                         "curPsTdma=%d, recordPsTdma=%d\n",
+                         coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type);
+
+               btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+               btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+               btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+               if (!scan && !link && !roam)
+                       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true,
+                                            coex_dm->tdma_adj_type);
+               else
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+                                 "[BTCoex], roaming/link/scan is under"
+                                 " progress, will adjust next time!!!\n");
+       }
+}
+
+/* SCO only or SCO+PAN(HS) */
+static void btc8723b2ant_action_sco(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                      0, 2, 15, 0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4);
+
+       if (btc8723b_need_dec_pwr(btcoexist))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+       /*for SCO quality at 11b/g mode*/
+       if (BTC_WIFI_BW_LEGACY == wifi_bw)
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 2);
+       else  /*for SCO quality & wifi performance balance at 11n mode*/
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 8);
+
+       /*for voice quality */
+       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0);
+
+       /* sw mechanism */
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  true, 0x4);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  true, 0x4);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  true, 0x4);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  true, 0x4);
+               }
+       }
+}
+
+static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state, bt_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                      0, 2, 15, 0);
+       bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+       if (btc8723b_need_dec_pwr(btcoexist))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+       if (BTC_WIFI_BW_LEGACY == wifi_bw) /*/for HID at 11b/g mode*/
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+       else  /*for HID quality & wifi performance balance at 11n mode*/
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 9);
+
+       if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+           (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+       else
+               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+
+       /* sw mechanism */
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       }
+}
+
+/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/
+static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state, bt_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                      0, 2, 15, 0);
+       bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+       if (btc8723b_need_dec_pwr(btcoexist))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+       if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+           (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+               btc8723b2ant_tdma_duration_adjust(btcoexist, false,
+                                                 false, 1);
+       else
+               btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 1);
+
+       /* sw mechanism */
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       }
+}
+
+static void btc8723b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                      0, 2, 15, 0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+       if (btc8723b_need_dec_pwr(btcoexist))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+       btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 2);
+
+       /* sw mechanism */
+       btcoexist->btc_get(btcoexist,
+               BTC_GET_U4_WIFI_BW, &wifi_bw);
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       }
+}
+
+static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state, bt_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                      0, 2, 15, 0);
+       bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+       if (btc8723b_need_dec_pwr(btcoexist))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 10);
+
+       if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+           (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1);
+       else
+               btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+
+       /* sw mechanism */
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       }
+}
+
+/*PAN(HS) only*/
+static void btc8723b2ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                      0, 2, 15, 0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+       if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+           (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+       btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       }
+}
+
+/*PAN(EDR)+A2DP*/
+static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state, bt_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                      0, 2, 15, 0);
+       bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+       if (btc8723b_need_dec_pwr(btcoexist))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+       if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+           (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 12);
+               if (BTC_WIFI_BW_HT40 == wifi_bw)
+                       btc8723b2ant_tdma_duration_adjust(btcoexist, false,
+                                                         true, 3);
+               else
+                       btc8723b2ant_tdma_duration_adjust(btcoexist, false,
+                                                         false, 3);
+       } else {
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+               btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 3);
+       }
+
+       /* sw mechanism */
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       }
+}
+
+static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state, bt_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                      0, 2, 15, 0);
+       bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+       if (btc8723b_need_dec_pwr(btcoexist))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+           (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+               if (BTC_WIFI_BW_HT40 == wifi_bw) {
+                       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC,
+                                                     3);
+                       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 11);
+                       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1,
+                                                 0xfffff, 0x780);
+               } else {
+                       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC,
+                                                     6);
+                       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+                       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1,
+                                                 0xfffff, 0x0);
+               }
+               btc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+       } else {
+               btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+               btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 11);
+               btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff,
+                                         0x0);
+               btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2);
+       }
+
+       /* sw mechanism */
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       }
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state, bt_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                      0, 2, 15, 0);
+       bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+       if (btc8723b_need_dec_pwr(btcoexist))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+       if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+           (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+               if (BTC_WIFI_BW_HT40 == wifi_bw)
+                       btc8723b2ant_tdma_duration_adjust(btcoexist, true,
+                                                         true, 2);
+               else
+                       btc8723b2ant_tdma_duration_adjust(btcoexist, true,
+                                                         false, 3);
+       } else {
+               btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 3);
+       }
+
+       /* sw mechanism */
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       }
+}
+
+static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+       u8 wifi_rssi_state, bt_rssi_state;
+       u32 wifi_bw;
+
+       wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
+                                                         0, 2, 15, 0);
+       bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+
+       btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+
+       btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+       if (btc8723b_need_dec_pwr(btcoexist))
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+       else
+               btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+       btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7);
+
+       if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+           (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
+               btc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+       else
+               btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2);
+
+       /* sw mechanism */
+       if (BTC_WIFI_BW_HT40 == wifi_bw) {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, true, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       } else {
+               if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+                   (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+                                                  false, 0x18);
+               } else {
+                       btc8723b2ant_sw_mechanism1(btcoexist, false, true,
+                                                  false, false);
+                       btc8723b2ant_sw_mechanism2(btcoexist, false, false,
+                                                  false, 0x18);
+               }
+       }
+}
+
+static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+       u8 algorithm = 0;
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                 "[BTCoex], RunCoexistMechanism()===>\n");
+
+       if (btcoexist->manual_control) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], RunCoexistMechanism(), "
+                         "return for Manual CTRL <===\n");
+               return;
+       }
+
+       if (coex_sta->under_ips) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], wifi is under IPS !!!\n");
+               return;
+       }
+
+       algorithm = btc8723b2ant_action_algorithm(btcoexist);
+       if (coex_sta->c2h_bt_inquiry_page &&
+           (BT_8723B_2ANT_COEX_ALGO_PANHS != algorithm)) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], BT is under inquiry/page scan !!\n");
+               btc8723b2ant_action_bt_inquiry(btcoexist);
+               return;
+       } else {
+               if (coex_dm->need_recover_0x948) {
+                       coex_dm->need_recover_0x948 = false;
+                       btcoexist->btc_write_2byte(btcoexist, 0x948,
+                                                  coex_dm->backup_0x948);
+               }
+       }
+
+       coex_dm->cur_algorithm = algorithm;
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Algorithm = %d\n",
+                 coex_dm->cur_algorithm);
+
+       if (btc8723b2ant_is_common_action(btcoexist)) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], Action 2-Ant common.\n");
+               coex_dm->auto_tdma_adjust = false;
+       } else {
+               if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) {
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], preAlgorithm=%d, "
+                                 "curAlgorithm=%d\n", coex_dm->pre_algorithm,
+                                 coex_dm->cur_algorithm);
+                       coex_dm->auto_tdma_adjust = false;
+               }
+               switch (coex_dm->cur_algorithm) {
+               case BT_8723B_2ANT_COEX_ALGO_SCO:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, algorithm = SCO.\n");
+                       btc8723b2ant_action_sco(btcoexist);
+                       break;
+               case BT_8723B_2ANT_COEX_ALGO_HID:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, algorithm = HID.\n");
+                       btc8723b2ant_action_hid(btcoexist);
+                       break;
+               case BT_8723B_2ANT_COEX_ALGO_A2DP:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, "
+                                 "algorithm = A2DP.\n");
+                       btc8723b2ant_action_a2dp(btcoexist);
+                       break;
+               case BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, "
+                                 "algorithm = A2DP+PAN(HS).\n");
+                       btc8723b2ant_action_a2dp_pan_hs(btcoexist);
+                       break;
+               case BT_8723B_2ANT_COEX_ALGO_PANEDR:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, "
+                                 "algorithm = PAN(EDR).\n");
+                       btc8723b2ant_action_pan_edr(btcoexist);
+                       break;
+               case BT_8723B_2ANT_COEX_ALGO_PANHS:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, "
+                                 "algorithm = HS mode.\n");
+                       btc8723b2ant_action_pan_hs(btcoexist);
+                               break;
+               case BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, "
+                                 "algorithm = PAN+A2DP.\n");
+                       btc8723b2ant_action_pan_edr_a2dp(btcoexist);
+                       break;
+               case BT_8723B_2ANT_COEX_ALGO_PANEDR_HID:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, "
+                                 "algorithm = PAN(EDR)+HID.\n");
+                       btc8723b2ant_action_pan_edr_hid(btcoexist);
+                       break;
+               case BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, "
+                                 "algorithm = HID+A2DP+PAN.\n");
+                       btc8723b2ant_action_hid_a2dp_pan_edr(btcoexist);
+                       break;
+               case BT_8723B_2ANT_COEX_ALGO_HID_A2DP:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, "
+                                 "algorithm = HID+A2DP.\n");
+                       btc8723b2ant_action_hid_a2dp(btcoexist);
+                       break;
+               default:
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], Action 2-Ant, "
+                                 "algorithm = coexist All Off!!\n");
+                       btc8723b2ant_coex_alloff(btcoexist);
+                       break;
+               }
+               coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+       }
+}
+
+
+
+/*********************************************************************
+ *  work around function start with wa_btc8723b2ant_
+ *********************************************************************/
+/*********************************************************************
+ *  extern function start with EXbtc8723b2ant_
+ *********************************************************************/
+void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+       struct btc_board_info *board_info = &btcoexist->board_info;
+       u32 u32tmp = 0, fw_ver;
+       u8 u8tmp = 0;
+       u8 h2c_parameter[2] = {0};
+
+
+       BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+                 "[BTCoex], 2Ant Init HW Config!!\n");
+
+       /* backup rf 0x1e value */
+       coex_dm->bt_rf0x1e_backup = btcoexist->btc_get_rf_reg(btcoexist,
+                                                             BTC_RF_A, 0x1e,
+                                                             0xfffff);
+
+       /* 0x4c[23]=0, 0x4c[24]=1  Antenna control by WL/BT */
+       u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+       u32tmp &= ~BIT23;
+       u32tmp |= BIT24;
+       btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+       btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
+       btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
+       btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
+       btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
+
+       /* Antenna switch control parameter */
+       /* btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);*/
+
+       /*Force GNT_BT to low*/
+       btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
+       btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+
+       /* 0x790[5:0]=0x5 */
+       u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+       u8tmp &= 0xc0;
+       u8tmp |= 0x5;
+       btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
+
+
+       /*Antenna config        */
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+
+ /*ext switch for fw ver < 0xc */
+       if (fw_ver < 0xc00) {
+               if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+                       btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+                                                          0x3, 0x1);
+                       /*Main Ant to  BT for IPS case 0x4c[23]=1*/
+                       btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
+                                                          0x1);
+
+                       /*tell firmware "no antenna inverse"*/
+                       h2c_parameter[0] = 0;
+                       h2c_parameter[1] = 1;  /* ext switch type */
+                       btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+                                               h2c_parameter);
+               } else {
+                       btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+                                                          0x3, 0x2);
+                       /*Aux Ant to  BT for IPS case 0x4c[23]=1*/
+                       btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
+                                                          0x0);
+
+                       /*tell firmware "antenna inverse"*/
+                       h2c_parameter[0] = 1;
+                       h2c_parameter[1] = 1;  /*ext switch type*/
+                       btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+                                               h2c_parameter);
+               }
+       } else {
+               /*ext switch always at s1 (if exist) */
+               btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1);
+               /*Main Ant to  BT for IPS case 0x4c[23]=1*/
+               btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x1);
+
+               if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+                       /*tell firmware "no antenna inverse"*/
+                       h2c_parameter[0] = 0;
+                       h2c_parameter[1] = 0;  /*ext switch type*/
+                       btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+                                               h2c_parameter);
+               } else {
+                       /*tell firmware "antenna inverse"*/
+                       h2c_parameter[0] = 1;
+                       h2c_parameter[1] = 0;  /*ext switch type*/
+                       btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+                                               h2c_parameter);
+               }
+       }
+
+       /* PTA parameter */
+       btc8723b_coex_tbl_type(btcoexist, FORCE_EXEC, 0);
+
+       /* Enable counter statistics */
+       /*0x76e[3] =1, WLAN_Act control by PTA*/
+       btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+       btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+       btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+}
+
+void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+       BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+                 "[BTCoex], Coex Mechanism Init!!\n");
+       btc8723b2ant_init_coex_dm(btcoexist);
+}
+
+void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+       struct btc_board_info *board_info = &btcoexist->board_info;
+       struct btc_stack_info *stack_info = &btcoexist->stack_info;
+       struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+       u8 *cli_buf = btcoexist->cli_buf;
+       u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+       u32 u32tmp[4];
+       bool roam = false, scan = false;
+       bool link = false, wifi_under_5g = false;
+       bool bt_hs_on = false, wifi_busy = false;
+       s32 wifi_rssi = 0, bt_hs_rssi = 0;
+       u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck;
+       u8 wifi_dot11_chnl, wifi_hs_chnl;
+       u32 fw_ver = 0, bt_patch_ver = 0;
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+                  "\r\n ============[BT Coexist info]============");
+       CL_PRINTF(cli_buf);
+
+       if (btcoexist->manual_control) {
+               CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+                          "\r\n ==========[Under Manual Control]============");
+               CL_PRINTF(cli_buf);
+               CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+                          "\r\n ==========================================");
+               CL_PRINTF(cli_buf);
+       }
+
+       if (!board_info->bt_exist) {
+               CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!");
+               CL_PRINTF(cli_buf);
+               return;
+       }
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ",
+                  "Ant PG number/ Ant mechanism:",
+                  board_info->pg_ant_num, board_info->btdm_ant_num);
+       CL_PRINTF(cli_buf);
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d",
+                  "BT stack/ hci ext ver",
+                  ((stack_info->profile_notified) ? "Yes" : "No"),
+                  stack_info->hci_version);
+       CL_PRINTF(cli_buf);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+                  "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
+                  "CoexVer/ FwVer/ PatchVer",
+                  glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant,
+                  fw_ver, bt_patch_ver, bt_patch_ver);
+       CL_PRINTF(cli_buf);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+       btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+                          &wifi_dot11_chnl);
+       btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)",
+                  "Dot11 channel / HsChnl(HsMode)",
+                  wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
+       CL_PRINTF(cli_buf);
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ",
+                  "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0],
+                  coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]);
+       CL_PRINTF(cli_buf);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+       btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+                  "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi);
+       CL_PRINTF(cli_buf);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+                  "Wifi link/ roam/ scan", link, roam, scan);
+       CL_PRINTF(cli_buf);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+       btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+                          &wifi_traffic_dir);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ",
+                  "Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
+                  ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+                  (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+                  ((!wifi_busy) ? "idle" :
+                  ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+                  "uplink" : "downlink")));
+       CL_PRINTF(cli_buf);
+
+       CL_PRINTF(cli_buf);
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d",
+                  "SCO/HID/PAN/A2DP",
+                  bt_link_info->sco_exist, bt_link_info->hid_exist,
+                  bt_link_info->pan_exist, bt_link_info->a2dp_exist);
+       CL_PRINTF(cli_buf);
+       btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+       bt_info_ext = coex_sta->bt_info_ext;
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s",
+                  "BT Info A2DP rate",
+                  (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
+       CL_PRINTF(cli_buf);
+
+       for (i = 0; i < BT_INFO_SRC_8723B_2ANT_MAX; i++) {
+               if (coex_sta->bt_info_c2h_cnt[i]) {
+                       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+                                  "\r\n %-35s = %02x %02x %02x "
+                                  "%02x %02x %02x %02x(%d)",
+                                  glbt_info_src_8723b_2ant[i],
+                                  coex_sta->bt_info_c2h[i][0],
+                                  coex_sta->bt_info_c2h[i][1],
+                                  coex_sta->bt_info_c2h[i][2],
+                                  coex_sta->bt_info_c2h[i][3],
+                                  coex_sta->bt_info_c2h[i][4],
+                                  coex_sta->bt_info_c2h[i][5],
+                                  coex_sta->bt_info_c2h[i][6],
+                                  coex_sta->bt_info_c2h_cnt[i]);
+                       CL_PRINTF(cli_buf);
+               }
+       }
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s",
+                  "PS state, IPS/LPS",
+                  ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+                  ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
+       CL_PRINTF(cli_buf);
+       btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+       /* Sw mechanism */
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+                  "\r\n %-35s", "============[Sw mechanism]============");
+       CL_PRINTF(cli_buf);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+                  "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink,
+                  coex_dm->cur_low_penalty_ra, coex_dm->limited_dig);
+       CL_PRINTF(cli_buf);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+                  "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
+                  coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
+                  coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
+       CL_PRINTF(cli_buf);
+
+       /* Fw mechanism */
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+                  "============[Fw mechanism]============");
+       CL_PRINTF(cli_buf);
+
+       ps_tdma_case = coex_dm->cur_ps_tdma;
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+                  "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+                  "PS TDMA", coex_dm->ps_tdma_para[0],
+                  coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
+                  coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
+                  ps_tdma_case, coex_dm->auto_tdma_adjust);
+       CL_PRINTF(cli_buf);
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ",
+                  "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr,
+                  coex_dm->cur_ignore_wlan_act);
+       CL_PRINTF(cli_buf);
+
+       /* Hw setting */
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+                  "============[Hw setting]============");
+       CL_PRINTF(cli_buf);
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x",
+                  "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup);
+       CL_PRINTF(cli_buf);
+
+       u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+       u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+                  "0x778/0x880[29:25]", u8tmp[0],
+                  (u32tmp[0]&0x3e000000) >> 25);
+       CL_PRINTF(cli_buf);
+
+       u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948);
+       u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67);
+       u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+                  "0x948/ 0x67[5] / 0x765",
+                  u32tmp[0], ((u8tmp[0]&0x20) >> 5), u8tmp[1]);
+       CL_PRINTF(cli_buf);
+
+       u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c);
+       u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930);
+       u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+                  "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]",
+                  u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3);
+       CL_PRINTF(cli_buf);
+
+
+       u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39);
+       u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+       u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+       u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+                  "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+                  "0x38[11]/0x40/0x4c[24:23]/0x64[0]",
+                  ((u8tmp[0] & 0x8)>>3), u8tmp[1],
+                  ((u32tmp[0]&0x01800000)>>23), u8tmp[2]&0x1);
+       CL_PRINTF(cli_buf);
+
+       u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+       u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+                  "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
+       CL_PRINTF(cli_buf);
+
+       u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+       u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+                  "0xc50(dig)/0x49c(null-drop)", u32tmp[0]&0xff, u8tmp[0]);
+       CL_PRINTF(cli_buf);
+
+       u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0);
+       u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4);
+       u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8);
+       u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0);
+
+       u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b);
+       u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+
+       fa_ofdm = ((u32tmp[0]&0xffff0000) >> 16) +
+                 ((u32tmp[1]&0xffff0000) >> 16) +
+                  (u32tmp[1] & 0xffff) +
+                  (u32tmp[2] & 0xffff) +
+                 ((u32tmp[3]&0xffff0000) >> 16) +
+                  (u32tmp[3] & 0xffff);
+       fa_cck = (u8tmp[0] << 8) + u8tmp[1];
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+                  "OFDM-CCA/OFDM-FA/CCK-FA",
+                  u32tmp[0]&0xffff, fa_ofdm, fa_cck);
+       CL_PRINTF(cli_buf);
+
+       u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+       u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+       u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+       u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+                  "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+                  "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
+                  u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]);
+       CL_PRINTF(cli_buf);
+
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+                  "0x770(high-pri rx/tx)",
+                  coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+       CL_PRINTF(cli_buf);
+       CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+                  "0x774(low-pri rx/tx)", coex_sta->low_priority_rx,
+                  coex_sta->low_priority_tx);
+       CL_PRINTF(cli_buf);
+#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1)
+       btc8723b2ant_monitor_bt_ctr(btcoexist);
+#endif
+       btcoexist->btc_disp_dbg_msg(btcoexist,
+       BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+
+void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+       if (BTC_IPS_ENTER == type) {
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], IPS ENTER notify\n");
+               coex_sta->under_ips = true;
+               btc8723b2ant_coex_alloff(btcoexist);
+       } else if (BTC_IPS_LEAVE == type) {
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], IPS LEAVE notify\n");
+               coex_sta->under_ips = false;
+       }
+}
+
+void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+       if (BTC_LPS_ENABLE == type) {
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], LPS ENABLE notify\n");
+               coex_sta->under_lps = true;
+       } else if (BTC_LPS_DISABLE == type) {
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], LPS DISABLE notify\n");
+               coex_sta->under_lps = false;
+       }
+}
+
+void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+       if (BTC_SCAN_START == type)
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], SCAN START notify\n");
+       else if (BTC_SCAN_FINISH == type)
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], SCAN FINISH notify\n");
+}
+
+void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+       if (BTC_ASSOCIATE_START == type)
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], CONNECT START notify\n");
+       else if (BTC_ASSOCIATE_FINISH == type)
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], CONNECT FINISH notify\n");
+}
+
+void btc8723b_med_stat_notify(struct btc_coexist *btcoexist,
+                                           u8 type)
+{
+       u8 h2c_parameter[3] = {0};
+       u32 wifi_bw;
+       u8 wifi_central_chnl;
+
+       if (BTC_MEDIA_CONNECT == type)
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], MEDIA connect notify\n");
+       else
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], MEDIA disconnect notify\n");
+
+       /* only 2.4G we need to inform bt the chnl mask */
+       btcoexist->btc_get(btcoexist,
+               BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifi_central_chnl);
+       if ((BTC_MEDIA_CONNECT == type) &&
+           (wifi_central_chnl <= 14)) {
+               h2c_parameter[0] = 0x1;
+               h2c_parameter[1] = wifi_central_chnl;
+               btcoexist->btc_get(btcoexist,
+                       BTC_GET_U4_WIFI_BW, &wifi_bw);
+               if (BTC_WIFI_BW_HT40 == wifi_bw)
+                       h2c_parameter[2] = 0x30;
+               else
+                       h2c_parameter[2] = 0x20;
+       }
+
+       coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+       coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+       coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+                 "[BTCoex], FW write 0x66=0x%x\n",
+                 h2c_parameter[0] << 16 | h2c_parameter[1] << 8 |
+                 h2c_parameter[2]);
+
+       btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+                                             u8 type)
+{
+       if (type == BTC_PACKET_DHCP)
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex], DHCP Packet notify\n");
+}
+
+void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+                                      u8 *tmpbuf, u8 length)
+{
+       u8 bt_info = 0;
+       u8 i, rsp_source = 0;
+       bool bt_busy = false, limited_dig = false;
+       bool wifi_connected = false;
+
+       coex_sta->c2h_bt_info_req_sent = false;
+
+       rsp_source = tmpbuf[0]&0xf;
+       if (rsp_source >= BT_INFO_SRC_8723B_2ANT_MAX)
+               rsp_source = BT_INFO_SRC_8723B_2ANT_WIFI_FW;
+       coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+       BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                 "[BTCoex], Bt info[%d], length=%d, hex data=[",
+                 rsp_source, length);
+       for (i = 0; i < length; i++) {
+               coex_sta->bt_info_c2h[rsp_source][i] = tmpbuf[i];
+               if (i == 1)
+                       bt_info = tmpbuf[i];
+               if (i == length-1)
+                       BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                                 "0x%02x]\n", tmpbuf[i]);
+               else
+                       BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                                 "0x%02x, ", tmpbuf[i]);
+       }
+
+       if (btcoexist->manual_control) {
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], BtInfoNotify(), "
+                         "return for Manual CTRL<===\n");
+               return;
+       }
+
+       if (BT_INFO_SRC_8723B_2ANT_WIFI_FW != rsp_source) {
+               coex_sta->bt_retry_cnt =        /* [3:0]*/
+                       coex_sta->bt_info_c2h[rsp_source][2] & 0xf;
+
+               coex_sta->bt_rssi =
+                       coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10;
+
+               coex_sta->bt_info_ext =
+                       coex_sta->bt_info_c2h[rsp_source][4];
+
+               /* Here we need to resend some wifi info to BT
+                * because bt is reset and loss of the info.
+                */
+               if ((coex_sta->bt_info_ext & BIT1)) {
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], BT ext info bit1 check,"
+                                 " send wifi BW&Chnl to BT!!\n");
+                       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+                                          &wifi_connected);
+                       if (wifi_connected)
+                               btc8723b_med_stat_notify(btcoexist,
+                                                        BTC_MEDIA_CONNECT);
+                       else
+                               btc8723b_med_stat_notify(btcoexist,
+                                                        BTC_MEDIA_DISCONNECT);
+               }
+
+               if ((coex_sta->bt_info_ext & BIT3)) {
+                       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                                 "[BTCoex], BT ext info bit3 check, "
+                                 "set BT NOT to ignore Wlan active!!\n");
+                       btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC,
+                                                    false);
+               } else {
+                       /* BT already NOT ignore Wlan active, do nothing here.*/
+               }
+#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0)
+               if ((coex_sta->bt_info_ext & BIT4)) {
+                       /* BT auto report already enabled, do nothing*/
+               } else {
+                       btc8723b2ant_bt_auto_report(btcoexist, FORCE_EXEC,
+                                                   true);
+               }
+#endif
+       }
+
+       /* check BIT2 first ==> check if bt is under inquiry or page scan*/
+       if (bt_info & BT_INFO_8723B_2ANT_B_INQ_PAGE)
+               coex_sta->c2h_bt_inquiry_page = true;
+       else
+               coex_sta->c2h_bt_inquiry_page = false;
+
+       /* set link exist status*/
+       if (!(bt_info & BT_INFO_8723B_2ANT_B_CONNECTION)) {
+               coex_sta->bt_link_exist = false;
+               coex_sta->pan_exist = false;
+               coex_sta->a2dp_exist = false;
+               coex_sta->hid_exist = false;
+               coex_sta->sco_exist = false;
+       } else { /*  connection exists */
+               coex_sta->bt_link_exist = true;
+               if (bt_info & BT_INFO_8723B_2ANT_B_FTP)
+                       coex_sta->pan_exist = true;
+               else
+                       coex_sta->pan_exist = false;
+               if (bt_info & BT_INFO_8723B_2ANT_B_A2DP)
+                       coex_sta->a2dp_exist = true;
+               else
+                       coex_sta->a2dp_exist = false;
+               if (bt_info & BT_INFO_8723B_2ANT_B_HID)
+                       coex_sta->hid_exist = true;
+               else
+                       coex_sta->hid_exist = false;
+               if (bt_info & BT_INFO_8723B_2ANT_B_SCO_ESCO)
+                       coex_sta->sco_exist = true;
+               else
+                       coex_sta->sco_exist = false;
+       }
+
+       btc8723b2ant_update_bt_link_info(btcoexist);
+
+       if (!(bt_info & BT_INFO_8723B_2ANT_B_CONNECTION)) {
+               coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE;
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], BtInfoNotify(), "
+                         "BT Non-Connected idle!!!\n");
+       /* connection exists but no busy */
+       } else if (bt_info == BT_INFO_8723B_2ANT_B_CONNECTION) {
+               coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE;
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n");
+       } else if ((bt_info & BT_INFO_8723B_2ANT_B_SCO_ESCO) ||
+                  (bt_info & BT_INFO_8723B_2ANT_B_SCO_BUSY)) {
+               coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_SCO_BUSY;
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
+       } else if (bt_info & BT_INFO_8723B_2ANT_B_ACL_BUSY) {
+               coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_ACL_BUSY;
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
+       } else {
+               coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_MAX;
+               BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                         "[BTCoex], BtInfoNotify(), "
+                         "BT Non-Defined state!!!\n");
+       }
+
+       if ((BT_8723B_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+           (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+           (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) {
+               bt_busy = true;
+               limited_dig = true;
+       } else {
+               bt_busy = false;
+               limited_dig = false;
+       }
+
+       btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+       coex_dm->limited_dig = limited_dig;
+       btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig);
+
+       btc8723b2ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+                                              u8 type)
+{
+       if (BTC_STACK_OP_INQ_PAGE_PAIR_START == type)
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex],StackOP Inquiry/page/pair start notify\n");
+       else if (BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type)
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+                         "[BTCoex],StackOP Inquiry/page/pair finish notify\n");
+}
+
+void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist)
+{
+       BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+
+       btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+       btc8723b_med_stat_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist)
+{
+       struct btc_board_info *board_info = &btcoexist->board_info;
+       struct btc_stack_info *stack_info = &btcoexist->stack_info;
+       static u8 dis_ver_info_cnt;
+       u32 fw_ver = 0, bt_patch_ver = 0;
+
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                 "[BTCoex], =========================="
+                 "Periodical===========================\n");
+
+       if (dis_ver_info_cnt <= 5) {
+               dis_ver_info_cnt += 1;
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+                         "[BTCoex], ****************************"
+                         "************************************\n");
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+                         "[BTCoex], Ant PG Num/ Ant Mech/ "
+                         "Ant Pos = %d/ %d/ %d\n", board_info->pg_ant_num,
+                         board_info->btdm_ant_num, board_info->btdm_ant_pos);
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+                         "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+                         ((stack_info->profile_notified) ? "Yes" : "No"),
+                         stack_info->hci_version);
+               btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+                                  &bt_patch_ver);
+               btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+                         "[BTCoex], CoexVer/ FwVer/ PatchVer = "
+                         "%d_%x/ 0x%x/ 0x%x(%d)\n",
+                         glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant,
+                         fw_ver, bt_patch_ver, bt_patch_ver);
+               BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+                         "[BTCoex], *****************************"
+                         "***********************************\n");
+       }
+
+#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0)
+       btc8723b2ant_query_bt_info(btcoexist);
+       btc8723b2ant_monitor_bt_ctr(btcoexist);
+       btc8723b2ant_monitor_bt_enable_disable(btcoexist);
+#else
+       if (btc8723b2ant_is_wifi_status_changed(btcoexist) ||
+           coex_dm->auto_tdma_adjust)
+               btc8723b2ant_run_coexist_mechanism(btcoexist);
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
new file mode 100644 (file)
index 0000000..e0ad8e5
--- /dev/null
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef _HAL8723B_2_ANT
+#define _HAL8723B_2_ANT
+
+/************************************************************************
+ * The following is for 8723B 2Ant BT Co-exist definition
+ ************************************************************************/
+#define        BT_AUTO_REPORT_ONLY_8723B_2ANT                  1
+
+#define        BT_INFO_8723B_2ANT_B_FTP                        BIT7
+#define        BT_INFO_8723B_2ANT_B_A2DP                       BIT6
+#define        BT_INFO_8723B_2ANT_B_HID                        BIT5
+#define        BT_INFO_8723B_2ANT_B_SCO_BUSY                   BIT4
+#define        BT_INFO_8723B_2ANT_B_ACL_BUSY                   BIT3
+#define        BT_INFO_8723B_2ANT_B_INQ_PAGE                   BIT2
+#define        BT_INFO_8723B_2ANT_B_SCO_ESCO                   BIT1
+#define        BT_INFO_8723B_2ANT_B_CONNECTION                 BIT0
+
+#define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT            2
+
+enum BT_INFO_SRC_8723B_2ANT {
+       BT_INFO_SRC_8723B_2ANT_WIFI_FW                  = 0x0,
+       BT_INFO_SRC_8723B_2ANT_BT_RSP                   = 0x1,
+       BT_INFO_SRC_8723B_2ANT_BT_ACTIVE_SEND           = 0x2,
+       BT_INFO_SRC_8723B_2ANT_MAX
+};
+
+enum BT_8723B_2ANT_BT_STATUS {
+       BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE      = 0x0,
+       BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE          = 0x1,
+       BT_8723B_2ANT_BT_STATUS_INQ_PAGE                = 0x2,
+       BT_8723B_2ANT_BT_STATUS_ACL_BUSY                = 0x3,
+       BT_8723B_2ANT_BT_STATUS_SCO_BUSY                = 0x4,
+       BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY            = 0x5,
+       BT_8723B_2ANT_BT_STATUS_MAX
+};
+
+enum BT_8723B_2ANT_COEX_ALGO {
+       BT_8723B_2ANT_COEX_ALGO_UNDEFINED               = 0x0,
+       BT_8723B_2ANT_COEX_ALGO_SCO                     = 0x1,
+       BT_8723B_2ANT_COEX_ALGO_HID                     = 0x2,
+       BT_8723B_2ANT_COEX_ALGO_A2DP                    = 0x3,
+       BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS              = 0x4,
+       BT_8723B_2ANT_COEX_ALGO_PANEDR                  = 0x5,
+       BT_8723B_2ANT_COEX_ALGO_PANHS                   = 0x6,
+       BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP             = 0x7,
+       BT_8723B_2ANT_COEX_ALGO_PANEDR_HID              = 0x8,
+       BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR         = 0x9,
+       BT_8723B_2ANT_COEX_ALGO_HID_A2DP                = 0xa,
+       BT_8723B_2ANT_COEX_ALGO_MAX                     = 0xb,
+};
+
+struct coex_dm_8723b_2ant {
+       /* fw mechanism */
+       bool pre_dec_bt_pwr;
+       bool cur_dec_bt_pwr;
+       u8 pre_fw_dac_swing_lvl;
+       u8 cur_fw_dac_swing_lvl;
+       bool cur_ignore_wlan_act;
+       bool pre_ignore_wlan_act;
+       u8 pre_ps_tdma;
+       u8 cur_ps_tdma;
+       u8 ps_tdma_para[5];
+       u8 tdma_adj_type;
+       bool reset_tdma_adjust;
+       bool auto_tdma_adjust;
+       bool pre_ps_tdma_on;
+       bool cur_ps_tdma_on;
+       bool pre_bt_auto_report;
+       bool cur_bt_auto_report;
+
+       /* sw mechanism */
+       bool pre_rf_rx_lpf_shrink;
+       bool cur_rf_rx_lpf_shrink;
+       u32 bt_rf0x1e_backup;
+       bool pre_low_penalty_ra;
+       bool cur_low_penalty_ra;
+       bool pre_dac_swing_on;
+       u32 pre_dac_swing_lvl;
+       bool cur_dac_swing_on;
+       u32 cur_dac_swing_lvl;
+       bool pre_adc_back_off;
+       bool cur_adc_back_off;
+       bool pre_agc_table_en;
+       bool cur_agc_table_en;
+       u32 pre_val0x6c0;
+       u32 cur_val0x6c0;
+       u32 pre_val0x6c4;
+       u32 cur_val0x6c4;
+       u32 pre_val0x6c8;
+       u32 cur_val0x6c8;
+       u8 pre_val0x6cc;
+       u8 cur_val0x6cc;
+       bool limited_dig;
+
+       /* algorithm related */
+       u8 pre_algorithm;
+       u8 cur_algorithm;
+       u8 bt_status;
+       u8 wifi_chnl_info[3];
+
+       bool need_recover_0x948;
+       u16 backup_0x948;
+};
+
+struct coex_sta_8723b_2ant {
+       bool bt_link_exist;
+       bool sco_exist;
+       bool a2dp_exist;
+       bool hid_exist;
+       bool pan_exist;
+
+       bool under_lps;
+       bool under_ips;
+       u32 high_priority_tx;
+       u32 high_priority_rx;
+       u32 low_priority_tx;
+       u32 low_priority_rx;
+       u8 bt_rssi;
+       u8 pre_bt_rssi_state;
+       u8 pre_wifi_rssi_state[4];
+       bool c2h_bt_info_req_sent;
+       u8 bt_info_c2h[BT_INFO_SRC_8723B_2ANT_MAX][10];
+       u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_2ANT_MAX];
+       bool c2h_bt_inquiry_page;
+       u8 bt_retry_cnt;
+       u8 bt_info_ext;
+};
+
+/*********************************************************************
+ * The following is interface which will notify coex module.
+ *********************************************************************/
+void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+                                             u8 type);
+void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+                                      u8 *tmpbuf, u8 length);
+void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+                                              u8 type);
+void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
new file mode 100644 (file)
index 0000000..b6722de
--- /dev/null
@@ -0,0 +1,1011 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2013 Realtek 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ******************************************************************************/
+
+#include "halbt_precomp.h"
+
+/***********************************************
+ *             Global variables
+ ***********************************************/
+
+struct btc_coexist gl_bt_coexist;
+
+u32 btc_dbg_type[BTC_MSG_MAX];
+static u8 btc_dbg_buf[100];
+
+/***************************************************
+ *             Debug related function
+ ***************************************************/
+static bool halbtc_is_bt_coexist_available(struct btc_coexist *btcoexist)
+{
+       if (!btcoexist->binded || NULL == btcoexist->adapter)
+               return false;
+
+       return true;
+}
+
+static bool halbtc_is_wifi_busy(struct rtl_priv *rtlpriv)
+{
+       if (rtlpriv->link_info.busytraffic)
+               return true;
+       else
+               return false;
+}
+
+static void halbtc_dbg_init(void)
+{
+       u8 i;
+
+       for (i = 0; i < BTC_MSG_MAX; i++)
+               btc_dbg_type[i] = 0;
+
+       btc_dbg_type[BTC_MSG_INTERFACE] =
+/*                     INTF_INIT                               | */
+/*                     INTF_NOTIFY                             | */
+                       0;
+
+       btc_dbg_type[BTC_MSG_ALGORITHM] =
+/*                     ALGO_BT_RSSI_STATE                      | */
+/*                     ALGO_WIFI_RSSI_STATE                    | */
+/*                     ALGO_BT_MONITOR                         | */
+/*                     ALGO_TRACE                              | */
+/*                     ALGO_TRACE_FW                           | */
+/*                     ALGO_TRACE_FW_DETAIL                    | */
+/*                     ALGO_TRACE_FW_EXEC                      | */
+/*                     ALGO_TRACE_SW                           | */
+/*                     ALGO_TRACE_SW_DETAIL                    | */
+/*                     ALGO_TRACE_SW_EXEC                      | */
+                       0;
+}
+
+static bool halbtc_is_bt40(struct rtl_priv *adapter)
+{
+       struct rtl_priv *rtlpriv = adapter;
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       bool is_ht40 = true;
+       enum ht_channel_width bw = rtlphy->current_chan_bw;
+
+       if (bw == HT_CHANNEL_WIDTH_20)
+               is_ht40 = false;
+       else if (bw == HT_CHANNEL_WIDTH_20_40)
+               is_ht40 = true;
+
+       return is_ht40;
+}
+
+static bool halbtc_legacy(struct rtl_priv *adapter)
+{
+       struct rtl_priv *rtlpriv = adapter;
+       struct rtl_mac *mac = rtl_mac(rtlpriv);
+
+       bool is_legacy = false;
+
+       if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_B))
+               is_legacy = true;
+
+       return is_legacy;
+}
+
+bool halbtc_is_wifi_uplink(struct rtl_priv *adapter)
+{
+       struct rtl_priv *rtlpriv = adapter;
+
+       if (rtlpriv->link_info.tx_busy_traffic)
+               return true;
+       else
+               return false;
+}
+
+static u32 halbtc_get_wifi_bw(struct btc_coexist *btcoexist)
+{
+       struct rtl_priv *rtlpriv =
+               (struct rtl_priv *)btcoexist->adapter;
+       u32 wifi_bw = BTC_WIFI_BW_HT20;
+
+       if (halbtc_is_bt40(rtlpriv)) {
+               wifi_bw = BTC_WIFI_BW_HT40;
+       } else {
+               if (halbtc_legacy(rtlpriv))
+                       wifi_bw = BTC_WIFI_BW_LEGACY;
+               else
+                       wifi_bw = BTC_WIFI_BW_HT20;
+       }
+       return wifi_bw;
+}
+
+static u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_phy  *rtlphy = &(rtlpriv->phy);
+       u8 chnl = 1;
+
+       if (rtlphy->current_channel != 0)
+               chnl = rtlphy->current_channel;
+       BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+                 "static halbtc_get_wifi_central_chnl:%d\n", chnl);
+       return chnl;
+}
+
+static void halbtc_leave_lps(struct btc_coexist *btcoexist)
+{
+       struct rtl_priv *rtlpriv;
+       struct rtl_ps_ctl *ppsc;
+       bool ap_enable = false;
+
+       rtlpriv = btcoexist->adapter;
+       ppsc = rtl_psc(rtlpriv);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+                          &ap_enable);
+
+       if (ap_enable) {
+               pr_info("halbtc_leave_lps()<--dont leave lps under AP mode\n");
+               return;
+       }
+
+       btcoexist->bt_info.bt_ctrl_lps = true;
+       btcoexist->bt_info.bt_lps_on = false;
+}
+
+static void halbtc_enter_lps(struct btc_coexist *btcoexist)
+{
+       struct rtl_priv *rtlpriv;
+       struct rtl_ps_ctl *ppsc;
+       bool ap_enable = false;
+
+       rtlpriv = btcoexist->adapter;
+       ppsc = rtl_psc(rtlpriv);
+
+       btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+                          &ap_enable);
+
+       if (ap_enable) {
+               pr_info("halbtc_enter_lps()<--dont enter lps under AP mode\n");
+               return;
+       }
+
+       btcoexist->bt_info.bt_ctrl_lps = true;
+       btcoexist->bt_info.bt_lps_on = false;
+}
+
+static void halbtc_normal_lps(struct btc_coexist *btcoexist)
+{
+       if (btcoexist->bt_info.bt_ctrl_lps) {
+               btcoexist->bt_info.bt_lps_on = false;
+               btcoexist->bt_info.bt_ctrl_lps = false;
+       }
+}
+
+static void halbtc_leave_low_power(void)
+{
+}
+
+static void halbtc_nomal_low_power(void)
+{
+}
+
+static void halbtc_disable_low_power(void)
+{
+}
+
+static void halbtc_aggregation_check(void)
+{
+}
+
+static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist)
+{
+       return 0;
+}
+
+static s32 halbtc_get_wifi_rssi(struct rtl_priv *adapter)
+{
+       struct rtl_priv *rtlpriv = adapter;
+       s32     undec_sm_pwdb = 0;
+
+       if (rtlpriv->mac80211.link_state >= MAC80211_LINKED)
+               undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
+       else /* associated entry pwdb */
+               undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
+       return undec_sm_pwdb;
+}
+
+static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtlpriv);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       bool *bool_tmp = (bool *)out_buf;
+       int *s32_tmp = (int *)out_buf;
+       u32 *u32_tmp = (u32 *)out_buf;
+       u8 *u8_tmp = (u8 *)out_buf;
+       bool tmp = false;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return false;
+
+       switch (get_type) {
+       case BTC_GET_BL_HS_OPERATION:
+               *bool_tmp = false;
+               break;
+       case BTC_GET_BL_HS_CONNECTING:
+               *bool_tmp = false;
+               break;
+       case BTC_GET_BL_WIFI_CONNECTED:
+               if (rtlpriv->mac80211.link_state >= MAC80211_LINKED)
+                       tmp = true;
+               *bool_tmp = tmp;
+               break;
+       case BTC_GET_BL_WIFI_BUSY:
+               if (halbtc_is_wifi_busy(rtlpriv))
+                       *bool_tmp = true;
+               else
+                       *bool_tmp = false;
+               break;
+       case BTC_GET_BL_WIFI_SCAN:
+               if (mac->act_scanning)
+                       *bool_tmp = true;
+               else
+                       *bool_tmp = false;
+               break;
+       case BTC_GET_BL_WIFI_LINK:
+               if (mac->link_state == MAC80211_LINKING)
+                       *bool_tmp = true;
+               else
+                       *bool_tmp = false;
+               break;
+       case BTC_GET_BL_WIFI_ROAM:      /*TODO*/
+               if (mac->link_state == MAC80211_LINKING)
+                       *bool_tmp = true;
+               else
+                       *bool_tmp = false;
+               break;
+       case BTC_GET_BL_WIFI_4_WAY_PROGRESS:    /*TODO*/
+                       *bool_tmp = false;
+
+               break;
+       case BTC_GET_BL_WIFI_UNDER_5G:
+               *bool_tmp = false; /*TODO*/
+
+       case BTC_GET_BL_WIFI_DHCP:      /*TODO*/
+               break;
+       case BTC_GET_BL_WIFI_SOFTAP_IDLE:
+               *bool_tmp = true;
+               break;
+       case BTC_GET_BL_WIFI_SOFTAP_LINKING:
+               *bool_tmp = false;
+               break;
+       case BTC_GET_BL_WIFI_IN_EARLY_SUSPEND:
+               *bool_tmp = false;
+               break;
+       case BTC_GET_BL_WIFI_AP_MODE_ENABLE:
+               *bool_tmp = false;
+               break;
+       case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION:
+               if (NO_ENCRYPTION == rtlpriv->sec.pairwise_enc_algorithm)
+                       *bool_tmp = false;
+               else
+                       *bool_tmp = true;
+               break;
+       case BTC_GET_BL_WIFI_UNDER_B_MODE:
+               *bool_tmp = false; /*TODO*/
+               break;
+       case BTC_GET_BL_EXT_SWITCH:
+               *bool_tmp = false;
+               break;
+       case BTC_GET_S4_WIFI_RSSI:
+               *s32_tmp = halbtc_get_wifi_rssi(rtlpriv);
+               break;
+       case BTC_GET_S4_HS_RSSI:        /*TODO*/
+               *s32_tmp = halbtc_get_wifi_rssi(rtlpriv);
+               break;
+       case BTC_GET_U4_WIFI_BW:
+               *u32_tmp = halbtc_get_wifi_bw(btcoexist);
+               break;
+       case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION:
+               if (halbtc_is_wifi_uplink(rtlpriv))
+                       *u32_tmp = BTC_WIFI_TRAFFIC_TX;
+               else
+                       *u32_tmp = BTC_WIFI_TRAFFIC_RX;
+               break;
+       case BTC_GET_U4_WIFI_FW_VER:
+               *u32_tmp = rtlhal->fw_version;
+               break;
+       case BTC_GET_U4_BT_PATCH_VER:
+               *u32_tmp = halbtc_get_bt_patch_version(btcoexist);
+               break;
+       case BTC_GET_U1_WIFI_DOT11_CHNL:
+               *u8_tmp = rtlphy->current_channel;
+               break;
+       case BTC_GET_U1_WIFI_CENTRAL_CHNL:
+               *u8_tmp = halbtc_get_wifi_central_chnl(btcoexist);
+               break;
+       case BTC_GET_U1_WIFI_HS_CHNL:
+               *u8_tmp = 1;/*BT_OperateChnl(rtlpriv);*/
+               break;
+       case BTC_GET_U1_MAC_PHY_MODE:
+               *u8_tmp = BTC_MP_UNKNOWN;
+               break;
+
+               /************* 1Ant **************/
+       case BTC_GET_U1_LPS_MODE:
+               *u8_tmp = btcoexist->pwr_mode_val[0];
+               break;
+
+       default:
+               break;
+       }
+
+       return true;
+}
+
+static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist;
+       bool *bool_tmp = (bool *)in_buf;
+       u8 *u8_tmp = (u8 *)in_buf;
+       u32 *u32_tmp = (u32 *)in_buf;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return false;
+
+       switch (set_type) {
+       /* set some bool type variables. */
+       case BTC_SET_BL_BT_DISABLE:
+               btcoexist->bt_info.bt_disabled = *bool_tmp;
+               break;
+       case BTC_SET_BL_BT_TRAFFIC_BUSY:
+               btcoexist->bt_info.bt_busy = *bool_tmp;
+               break;
+       case BTC_SET_BL_BT_LIMITED_DIG:
+               btcoexist->bt_info.limited_dig = *bool_tmp;
+               break;
+       case BTC_SET_BL_FORCE_TO_ROAM:
+               btcoexist->bt_info.force_to_roam = *bool_tmp;
+               break;
+       case BTC_SET_BL_TO_REJ_AP_AGG_PKT:
+               btcoexist->bt_info.reject_agg_pkt = *bool_tmp;
+               break;
+       case BTC_SET_BL_BT_CTRL_AGG_SIZE:
+               btcoexist->bt_info.b_bt_ctrl_buf_size = *bool_tmp;
+               break;
+       case BTC_SET_BL_INC_SCAN_DEV_NUM:
+               btcoexist->bt_info.increase_scan_dev_num = *bool_tmp;
+               break;
+               /* set some u1Byte type variables. */
+       case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON:
+               btcoexist->bt_info.rssi_adjust_for_agc_table_on = *u8_tmp;
+               break;
+       case BTC_SET_U1_AGG_BUF_SIZE:
+               btcoexist->bt_info.agg_buf_size = *u8_tmp;
+               break;
+               /* the following are some action which will be triggered */
+       case BTC_SET_ACT_GET_BT_RSSI:
+               /*BTHCI_SendGetBtRssiEvent(rtlpriv);*/
+               break;
+       case BTC_SET_ACT_AGGREGATE_CTRL:
+               halbtc_aggregation_check();
+               break;
+
+               /* 1Ant */
+       case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE:
+               btcoexist->bt_info.rssi_adjust_for_1ant_coex_type = *u8_tmp;
+               break;
+       case BTC_SET_UI_SCAN_SIG_COMPENSATION:
+       /*      rtlpriv->mlmepriv.scan_compensation = *u8_tmp;  */
+               break;
+       case BTC_SET_U1_1ANT_LPS:
+               btcoexist->bt_info.lps_1ant = *u8_tmp;
+               break;
+       case BTC_SET_U1_1ANT_RPWM:
+               btcoexist->bt_info.rpwm_1ant = *u8_tmp;
+               break;
+       /* the following are some action which will be triggered  */
+       case BTC_SET_ACT_LEAVE_LPS:
+               halbtc_leave_lps(btcoexist);
+               break;
+       case BTC_SET_ACT_ENTER_LPS:
+               halbtc_enter_lps(btcoexist);
+               break;
+       case BTC_SET_ACT_NORMAL_LPS:
+               halbtc_normal_lps(btcoexist);
+               break;
+       case BTC_SET_ACT_DISABLE_LOW_POWER:
+               halbtc_disable_low_power();
+               break;
+       case BTC_SET_ACT_UPDATE_ra_mask:
+               btcoexist->bt_info.ra_mask = *u32_tmp;
+               break;
+       case BTC_SET_ACT_SEND_MIMO_PS:
+               break;
+       case BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT:
+               btcoexist->bt_info.force_exec_pwr_cmd_cnt++;
+               break;
+       case BTC_SET_ACT_CTRL_BT_INFO: /*wait for 8812/8821*/
+               break;
+       case BTC_SET_ACT_CTRL_BT_COEX:
+               break;
+       default:
+               break;
+       }
+
+       return true;
+}
+
+static void halbtc_display_coex_statistics(struct btc_coexist *btcoexist)
+{
+}
+
+static void halbtc_display_bt_link_info(struct btc_coexist *btcoexist)
+{
+}
+
+static void halbtc_display_bt_fw_info(struct btc_coexist *btcoexist)
+{
+}
+
+static void halbtc_display_fw_pwr_mode_cmd(struct btc_coexist *btcoexist)
+{
+}
+
+/************************************************************
+ *             IO related function
+ ************************************************************/
+static u8 halbtc_read_1byte(void *bt_context, u32 reg_addr)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       return  rtl_read_byte(rtlpriv, reg_addr);
+}
+
+static u16 halbtc_read_2byte(void *bt_context, u32 reg_addr)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       return  rtl_read_word(rtlpriv, reg_addr);
+}
+
+static u32 halbtc_read_4byte(void *bt_context, u32 reg_addr)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       return  rtl_read_dword(rtlpriv, reg_addr);
+}
+
+static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       rtl_write_byte(rtlpriv, reg_addr, data);
+}
+
+static void halbtc_bitmask_write_1byte(void *bt_context, u32 reg_addr,
+                                      u32 bit_mask, u8 data)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       u8 original_value, bit_shift = 0;
+       u8 i;
+
+       if (bit_mask != MASKDWORD) {/*if not "double word" write*/
+               original_value = rtl_read_byte(rtlpriv, reg_addr);
+               for (i = 0; i <= 7; i++) {
+                       if ((bit_mask>>i) & 0x1)
+                               break;
+               }
+               bit_shift = i;
+               data = (original_value & (~bit_mask)) |
+                       ((data << bit_shift) & bit_mask);
+       }
+       rtl_write_byte(rtlpriv, reg_addr, data);
+}
+
+static void halbtc_write_2byte(void *bt_context, u32 reg_addr, u16 data)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       rtl_write_word(rtlpriv, reg_addr, data);
+}
+
+static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data)
+{
+       struct btc_coexist *btcoexist =
+               (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       rtl_write_dword(rtlpriv, reg_addr, data);
+}
+
+static void halbtc_set_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask,
+                            u32 data)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data);
+}
+
+static u32 halbtc_get_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       return rtl_get_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask);
+}
+
+static void halbtc_set_rfreg(void *bt_context, u8 rf_path, u32 reg_addr,
+                            u32 bit_mask, u32 data)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       rtl_set_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask, data);
+}
+
+static u32 halbtc_get_rfreg(void *bt_context, u8 rf_path, u32 reg_addr,
+                           u32 bit_mask)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       return rtl_get_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask);
+}
+
+static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id,
+                               u32 cmd_len, u8 *cmd_buf)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+       rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, element_id,
+                                       cmd_len, cmd_buf);
+}
+
+static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type)
+{
+       struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
+       switch (disp_type) {
+       case BTC_DBG_DISP_COEX_STATISTICS:
+               halbtc_display_coex_statistics(btcoexist);
+               break;
+       case BTC_DBG_DISP_BT_LINK_INFO:
+               halbtc_display_bt_link_info(btcoexist);
+               break;
+       case BTC_DBG_DISP_BT_FW_VER:
+               halbtc_display_bt_fw_info(btcoexist);
+               break;
+       case BTC_DBG_DISP_FW_PWR_MODE_CMD:
+               halbtc_display_fw_pwr_mode_cmd(btcoexist);
+               break;
+       default:
+               break;
+       }
+}
+
+/*****************************************************************
+ *         Extern functions called by other module
+ *****************************************************************/
+bool exhalbtc_initlize_variables(struct rtl_priv *adapter)
+{
+       struct btc_coexist *btcoexist = &gl_bt_coexist;
+
+       btcoexist->statistics.cnt_bind++;
+
+       halbtc_dbg_init();
+
+       if (btcoexist->binded)
+               return false;
+       else
+               btcoexist->binded = true;
+
+#if (defined(CONFIG_PCI_HCI))
+       btcoexist->chip_interface = BTC_INTF_PCI;
+#elif (defined(CONFIG_USB_HCI))
+       btcoexist->chip_interface = BTC_INTF_USB;
+#elif (defined(CONFIG_SDIO_HCI))
+       btcoexist->chip_interface = BTC_INTF_SDIO;
+#elif (defined(CONFIG_GSPI_HCI))
+       btcoexist->chip_interface = BTC_INTF_GSPI;
+#else
+       btcoexist->chip_interface = BTC_INTF_UNKNOWN;
+#endif
+
+       if (NULL == btcoexist->adapter)
+               btcoexist->adapter = adapter;
+
+       btcoexist->stack_info.profile_notified = false;
+
+       btcoexist->btc_read_1byte = halbtc_read_1byte;
+       btcoexist->btc_write_1byte = halbtc_write_1byte;
+       btcoexist->btc_write_1byte_bitmask = halbtc_bitmask_write_1byte;
+       btcoexist->btc_read_2byte = halbtc_read_2byte;
+       btcoexist->btc_write_2byte = halbtc_write_2byte;
+       btcoexist->btc_read_4byte = halbtc_read_4byte;
+       btcoexist->btc_write_4byte = halbtc_write_4byte;
+
+       btcoexist->btc_set_bb_reg = halbtc_set_bbreg;
+       btcoexist->btc_get_bb_reg = halbtc_get_bbreg;
+
+       btcoexist->btc_set_rf_reg = halbtc_set_rfreg;
+       btcoexist->btc_get_rf_reg = halbtc_get_rfreg;
+
+       btcoexist->btc_fill_h2c = halbtc_fill_h2c_cmd;
+       btcoexist->btc_disp_dbg_msg = halbtc_display_dbg_msg;
+
+       btcoexist->btc_get = halbtc_get;
+       btcoexist->btc_set = halbtc_set;
+
+       btcoexist->cli_buf = &btc_dbg_buf[0];
+
+       btcoexist->bt_info.b_bt_ctrl_buf_size = false;
+       btcoexist->bt_info.agg_buf_size = 5;
+
+       btcoexist->bt_info.increase_scan_dev_num = false;
+       return true;
+}
+
+void exhalbtc_init_hw_config(struct btc_coexist *btcoexist)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+
+       btcoexist->statistics.cnt_init_hw_config++;
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_init_hwconfig(btcoexist);
+}
+
+void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+
+       btcoexist->statistics.cnt_init_coex_dm++;
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_init_coex_dm(btcoexist);
+
+       btcoexist->initilized = true;
+}
+
+void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 ips_type;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_ips_notify++;
+       if (btcoexist->manual_control)
+               return;
+
+       if (ERFOFF == type)
+               ips_type = BTC_IPS_ENTER;
+       else
+               ips_type = BTC_IPS_LEAVE;
+
+       halbtc_leave_low_power();
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_ips_notify(btcoexist, ips_type);
+
+       halbtc_nomal_low_power();
+}
+
+void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 lps_type;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_lps_notify++;
+       if (btcoexist->manual_control)
+               return;
+
+       if (EACTIVE == type)
+               lps_type = BTC_LPS_DISABLE;
+       else
+               lps_type = BTC_LPS_ENABLE;
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_lps_notify(btcoexist, lps_type);
+}
+
+void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 scan_type;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_scan_notify++;
+       if (btcoexist->manual_control)
+               return;
+
+       if (type)
+               scan_type = BTC_SCAN_START;
+       else
+               scan_type = BTC_SCAN_FINISH;
+
+       halbtc_leave_low_power();
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_scan_notify(btcoexist, scan_type);
+
+       halbtc_nomal_low_power();
+}
+
+void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 asso_type;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_connect_notify++;
+       if (btcoexist->manual_control)
+               return;
+
+       if (action)
+               asso_type = BTC_ASSOCIATE_START;
+       else
+               asso_type = BTC_ASSOCIATE_FINISH;
+
+       halbtc_leave_low_power();
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_connect_notify(btcoexist, asso_type);
+}
+
+void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
+                                enum _RT_MEDIA_STATUS media_status)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 status;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_media_status_notify++;
+       if (btcoexist->manual_control)
+               return;
+
+       if (RT_MEDIA_CONNECT == media_status)
+               status = BTC_MEDIA_CONNECT;
+       else
+               status = BTC_MEDIA_DISCONNECT;
+
+       halbtc_leave_low_power();
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               btc8723b_med_stat_notify(btcoexist, status);
+
+       halbtc_nomal_low_power();
+}
+
+void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 packet_type;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_special_packet_notify++;
+       if (btcoexist->manual_control)
+               return;
+
+       packet_type = BTC_PACKET_DHCP;
+
+       halbtc_leave_low_power();
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_special_packet_notify(btcoexist,
+                                                        packet_type);
+
+       halbtc_nomal_low_power();
+}
+
+void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist,
+                            u8 *tmp_buf, u8 length)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_bt_info_notify++;
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length);
+}
+
+void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 stack_op_type;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_stack_operation_notify++;
+       if (btcoexist->manual_control)
+               return;
+
+       stack_op_type = BTC_STACK_OP_NONE;
+
+       halbtc_leave_low_power();
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_stack_operation_notify(btcoexist,
+                                                         stack_op_type);
+
+       halbtc_nomal_low_power();
+}
+
+void exhalbtc_halt_notify(struct btc_coexist *btcoexist)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_halt_notify(btcoexist);
+}
+
+void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
+{
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+}
+
+void exhalbtc_periodical(struct btc_coexist *btcoexist)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_periodical++;
+
+       halbtc_leave_low_power();
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_periodical(btcoexist);
+
+       halbtc_nomal_low_power();
+}
+
+void exhalbtc_dbg_control(struct btc_coexist *btcoexist,
+                         u8 code, u8 len, u8 *data)
+{
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+       btcoexist->statistics.cnt_dbg_ctrl++;
+}
+
+void exhalbtc_stack_update_profile_info(void)
+{
+}
+
+void exhalbtc_update_min_bt_rssi(char bt_rssi)
+{
+       struct btc_coexist *btcoexist = &gl_bt_coexist;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+
+       btcoexist->stack_info.min_bt_rssi = bt_rssi;
+}
+
+void exhalbtc_set_hci_version(u16 hci_version)
+{
+       struct btc_coexist *btcoexist = &gl_bt_coexist;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+
+       btcoexist->stack_info.hci_version = hci_version;
+}
+
+void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version)
+{
+       struct btc_coexist *btcoexist = &gl_bt_coexist;
+
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+
+       btcoexist->bt_info.bt_real_fw_ver = bt_patch_version;
+       btcoexist->bt_info.bt_hci_ver = bt_hci_version;
+}
+
+void exhalbtc_set_bt_exist(bool bt_exist)
+{
+       gl_bt_coexist.board_info.bt_exist = bt_exist;
+}
+
+void exhalbtc_set_chip_type(u8 chip_type)
+{
+       switch (chip_type) {
+       default:
+       case BT_2WIRE:
+       case BT_ISSC_3WIRE:
+       case BT_ACCEL:
+       case BT_RTL8756:
+               gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_UNDEF;
+               break;
+       case BT_CSR_BC4:
+               gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC4;
+               break;
+       case BT_CSR_BC8:
+               gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC8;
+               break;
+       case BT_RTL8723A:
+               gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723A;
+               break;
+       case BT_RTL8821A:
+               gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8821;
+               break;
+       case BT_RTL8723B:
+               gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723B;
+               break;
+       }
+}
+
+void exhalbtc_set_ant_num(u8 type, u8 ant_num)
+{
+       if (BT_COEX_ANT_TYPE_PG == type) {
+               gl_bt_coexist.board_info.pg_ant_num = ant_num;
+               gl_bt_coexist.board_info.btdm_ant_num = ant_num;
+       } else if (BT_COEX_ANT_TYPE_ANTDIV == type) {
+               gl_bt_coexist.board_info.btdm_ant_num = ant_num;
+       }
+}
+
+void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist)
+{
+       struct rtl_priv *rtlpriv = btcoexist->adapter;
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       if (!halbtc_is_bt_coexist_available(btcoexist))
+               return;
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
+               ex_halbtc8723b2ant_display_coex_info(btcoexist);
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
new file mode 100644 (file)
index 0000000..871fc3c
--- /dev/null
@@ -0,0 +1,559 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef        __HALBTC_OUT_SRC_H__
+#define __HALBTC_OUT_SRC_H__
+
+#include       "../wifi.h"
+
+#define                NORMAL_EXEC                             false
+#define                FORCE_EXEC                              true
+
+#define                BTC_RF_A                                RF90_PATH_A
+#define                BTC_RF_B                                RF90_PATH_B
+#define                BTC_RF_C                                RF90_PATH_C
+#define                BTC_RF_D                                RF90_PATH_D
+
+#define                BTC_SMSP                                SINGLEMAC_SINGLEPHY
+#define                BTC_DMDP                                DUALMAC_DUALPHY
+#define                BTC_DMSP                                DUALMAC_SINGLEPHY
+#define                BTC_MP_UNKNOWN                          0xff
+
+#define                IN
+#define                OUT
+
+#define                BT_TMP_BUF_SIZE                         100
+
+#define                BT_COEX_ANT_TYPE_PG                     0
+#define                BT_COEX_ANT_TYPE_ANTDIV                 1
+#define                BT_COEX_ANT_TYPE_DETECTED               2
+
+#define                BTC_MIMO_PS_STATIC                      0
+#define                BTC_MIMO_PS_DYNAMIC                     1
+
+#define                BTC_RATE_DISABLE                        0
+#define                BTC_RATE_ENABLE                         1
+
+#define                BTC_ANT_PATH_WIFI                       0
+#define                BTC_ANT_PATH_BT                         1
+#define                BTC_ANT_PATH_PTA                        2
+
+enum btc_chip_interface {
+       BTC_INTF_UNKNOWN        = 0,
+       BTC_INTF_PCI            = 1,
+       BTC_INTF_USB            = 2,
+       BTC_INTF_SDIO           = 3,
+       BTC_INTF_GSPI           = 4,
+       BTC_INTF_MAX
+};
+
+enum BTC_CHIP_TYPE {
+       BTC_CHIP_UNDEF          = 0,
+       BTC_CHIP_CSR_BC4        = 1,
+       BTC_CHIP_CSR_BC8        = 2,
+       BTC_CHIP_RTL8723A       = 3,
+       BTC_CHIP_RTL8821        = 4,
+       BTC_CHIP_RTL8723B       = 5,
+       BTC_CHIP_MAX
+};
+
+enum BTC_MSG_TYPE {
+       BTC_MSG_INTERFACE       = 0x0,
+       BTC_MSG_ALGORITHM       = 0x1,
+       BTC_MSG_MAX
+};
+extern u32 btc_dbg_type[];
+
+/* following is for BTC_MSG_INTERFACE */
+#define                INTF_INIT                               BIT0
+#define                INTF_NOTIFY                             BIT2
+
+/* following is for BTC_ALGORITHM */
+#define                ALGO_BT_RSSI_STATE                      BIT0
+#define                ALGO_WIFI_RSSI_STATE                    BIT1
+#define                ALGO_BT_MONITOR                         BIT2
+#define                ALGO_TRACE                              BIT3
+#define                ALGO_TRACE_FW                           BIT4
+#define                ALGO_TRACE_FW_DETAIL                    BIT5
+#define                ALGO_TRACE_FW_EXEC                      BIT6
+#define                ALGO_TRACE_SW                           BIT7
+#define                ALGO_TRACE_SW_DETAIL                    BIT8
+#define                ALGO_TRACE_SW_EXEC                      BIT9
+
+#define                BT_COEX_ANT_TYPE_PG                     0
+#define                BT_COEX_ANT_TYPE_ANTDIV                 1
+#define                BT_COEX_ANT_TYPE_DETECTED               2
+#define                BTC_MIMO_PS_STATIC                      0
+#define                BTC_MIMO_PS_DYNAMIC                     1
+#define                BTC_RATE_DISABLE                        0
+#define                BTC_RATE_ENABLE                         1
+#define                BTC_ANT_PATH_WIFI                       0
+#define                BTC_ANT_PATH_BT                         1
+#define                BTC_ANT_PATH_PTA                        2
+
+
+#define        CL_SPRINTF      snprintf
+#define        CL_PRINTF       printk
+
+#define        BTC_PRINT(dbgtype, dbgflag, printstr, ...)              \
+       do {                                                    \
+               if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\
+                       printk(printstr, ##__VA_ARGS__);        \
+               }                                               \
+       } while (0)
+
+#define        BTC_PRINT_F(dbgtype, dbgflag, printstr, ...)            \
+       do {                                                    \
+               if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\
+                       pr_info("%s: ", __func__);      \
+                       printk(printstr, ##__VA_ARGS__);        \
+               }                                               \
+       } while (0)
+
+#define        BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _ptr)        \
+       do {                                                    \
+               if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {        \
+                       int __i;                                \
+                       u8 *__ptr = (u8 *)_ptr;                 \
+                       printk printstr;                        \
+                       for (__i = 0; __i < 6; __i++)           \
+                               printk("%02X%s", __ptr[__i], (__i == 5) ? \
+                                      "" : "-");               \
+                       pr_info("\n");                          \
+               }                                               \
+       } while (0)
+
+#define BTC_PRINT_DATA(dbgtype, dbgflag, _titlestring, _hexdata, _hexdatalen) \
+       do {                                                            \
+               if (unlikely(btc_dbg_type[dbgtype] & dbgflag))  {       \
+                       int __i;                                        \
+                       u8 *__ptr = (u8 *)_hexdata;                     \
+                       printk(_titlestring);                           \
+                       for (__i = 0; __i < (int)_hexdatalen; __i++) {  \
+                               printk("%02X%s", __ptr[__i], (((__i + 1) % 4) \
+                                                       == 0) ? "  " : " ");\
+                               if (((__i + 1) % 16) == 0)              \
+                                       printk("\n");                   \
+                       }                                               \
+                       pr_debug("\n");                                 \
+               }                                                       \
+       } while (0)
+
+#define BTC_ANT_PATH_WIFI      0
+#define BTC_ANT_PATH_BT                1
+#define BTC_ANT_PATH_PTA       2
+
+enum btc_power_save_type {
+       BTC_PS_WIFI_NATIVE = 0,
+       BTC_PS_LPS_ON = 1,
+       BTC_PS_LPS_OFF = 2,
+       BTC_PS_LPS_MAX
+};
+
+struct btc_board_info {
+       /* The following is some board information */
+       u8 bt_chip_type;
+       u8 pg_ant_num;  /* pg ant number */
+       u8 btdm_ant_num;        /* ant number for btdm */
+       u8 btdm_ant_pos;
+       bool bt_exist;
+};
+
+enum btc_dbg_opcode {
+       BTC_DBG_SET_COEX_NORMAL = 0x0,
+       BTC_DBG_SET_COEX_WIFI_ONLY = 0x1,
+       BTC_DBG_SET_COEX_BT_ONLY = 0x2,
+       BTC_DBG_MAX
+};
+
+enum btc_rssi_state {
+       BTC_RSSI_STATE_HIGH = 0x0,
+       BTC_RSSI_STATE_MEDIUM = 0x1,
+       BTC_RSSI_STATE_LOW = 0x2,
+       BTC_RSSI_STATE_STAY_HIGH = 0x3,
+       BTC_RSSI_STATE_STAY_MEDIUM = 0x4,
+       BTC_RSSI_STATE_STAY_LOW = 0x5,
+       BTC_RSSI_MAX
+};
+
+enum btc_wifi_role {
+       BTC_ROLE_STATION = 0x0,
+       BTC_ROLE_AP = 0x1,
+       BTC_ROLE_IBSS = 0x2,
+       BTC_ROLE_HS_MODE = 0x3,
+       BTC_ROLE_MAX
+};
+
+enum btc_wifi_bw_mode {
+       BTC_WIFI_BW_LEGACY = 0x0,
+       BTC_WIFI_BW_HT20 = 0x1,
+       BTC_WIFI_BW_HT40 = 0x2,
+       BTC_WIFI_BW_MAX
+};
+
+enum btc_wifi_traffic_dir {
+       BTC_WIFI_TRAFFIC_TX = 0x0,
+       BTC_WIFI_TRAFFIC_RX = 0x1,
+       BTC_WIFI_TRAFFIC_MAX
+};
+
+enum btc_wifi_pnp {
+       BTC_WIFI_PNP_WAKE_UP = 0x0,
+       BTC_WIFI_PNP_SLEEP = 0x1,
+       BTC_WIFI_PNP_MAX
+};
+
+
+enum btc_get_type {
+       /* type bool */
+       BTC_GET_BL_HS_OPERATION,
+       BTC_GET_BL_HS_CONNECTING,
+       BTC_GET_BL_WIFI_CONNECTED,
+       BTC_GET_BL_WIFI_BUSY,
+       BTC_GET_BL_WIFI_SCAN,
+       BTC_GET_BL_WIFI_LINK,
+       BTC_GET_BL_WIFI_DHCP,
+       BTC_GET_BL_WIFI_SOFTAP_IDLE,
+       BTC_GET_BL_WIFI_SOFTAP_LINKING,
+       BTC_GET_BL_WIFI_IN_EARLY_SUSPEND,
+       BTC_GET_BL_WIFI_ROAM,
+       BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+       BTC_GET_BL_WIFI_UNDER_5G,
+       BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+       BTC_GET_BL_WIFI_ENABLE_ENCRYPTION,
+       BTC_GET_BL_WIFI_UNDER_B_MODE,
+       BTC_GET_BL_EXT_SWITCH,
+
+       /* type s4Byte */
+       BTC_GET_S4_WIFI_RSSI,
+       BTC_GET_S4_HS_RSSI,
+
+       /* type u32 */
+       BTC_GET_U4_WIFI_BW,
+       BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+       BTC_GET_U4_WIFI_FW_VER,
+       BTC_GET_U4_BT_PATCH_VER,
+
+       /* type u1Byte */
+       BTC_GET_U1_WIFI_DOT11_CHNL,
+       BTC_GET_U1_WIFI_CENTRAL_CHNL,
+       BTC_GET_U1_WIFI_HS_CHNL,
+       BTC_GET_U1_MAC_PHY_MODE,
+
+       /* for 1Ant */
+       BTC_GET_U1_LPS_MODE,
+       BTC_GET_BL_BT_SCO_BUSY,
+
+       /* for test mode */
+       BTC_GET_DRIVER_TEST_CFG,
+       BTC_GET_MAX
+};
+
+
+enum btc_set_type {
+       /* type bool */
+       BTC_SET_BL_BT_DISABLE,
+       BTC_SET_BL_BT_TRAFFIC_BUSY,
+       BTC_SET_BL_BT_LIMITED_DIG,
+       BTC_SET_BL_FORCE_TO_ROAM,
+       BTC_SET_BL_TO_REJ_AP_AGG_PKT,
+       BTC_SET_BL_BT_CTRL_AGG_SIZE,
+       BTC_SET_BL_INC_SCAN_DEV_NUM,
+
+       /* type u1Byte */
+       BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON,
+       BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
+       BTC_SET_UI_SCAN_SIG_COMPENSATION,
+       BTC_SET_U1_AGG_BUF_SIZE,
+
+       /* type trigger some action */
+       BTC_SET_ACT_GET_BT_RSSI,
+       BTC_SET_ACT_AGGREGATE_CTRL,
+
+       /********* for 1Ant **********/
+       /* type bool */
+       BTC_SET_BL_BT_SCO_BUSY,
+       /* type u1Byte */
+       BTC_SET_U1_1ANT_LPS,
+       BTC_SET_U1_1ANT_RPWM,
+       /* type trigger some action */
+       BTC_SET_ACT_LEAVE_LPS,
+       BTC_SET_ACT_ENTER_LPS,
+       BTC_SET_ACT_NORMAL_LPS,
+       BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT,
+       BTC_SET_ACT_DISABLE_LOW_POWER,
+       BTC_SET_ACT_UPDATE_ra_mask,
+       BTC_SET_ACT_SEND_MIMO_PS,
+       /* BT Coex related */
+       BTC_SET_ACT_CTRL_BT_INFO,
+       BTC_SET_ACT_CTRL_BT_COEX,
+       /***************************/
+       BTC_SET_MAX
+};
+
+enum btc_dbg_disp_type {
+       BTC_DBG_DISP_COEX_STATISTICS = 0x0,
+       BTC_DBG_DISP_BT_LINK_INFO = 0x1,
+       BTC_DBG_DISP_BT_FW_VER = 0x2,
+       BTC_DBG_DISP_FW_PWR_MODE_CMD = 0x3,
+       BTC_DBG_DISP_MAX
+};
+
+enum btc_notify_type_ips {
+       BTC_IPS_LEAVE = 0x0,
+       BTC_IPS_ENTER = 0x1,
+       BTC_IPS_MAX
+};
+
+enum btc_notify_type_lps {
+       BTC_LPS_DISABLE = 0x0,
+       BTC_LPS_ENABLE = 0x1,
+       BTC_LPS_MAX
+};
+
+enum btc_notify_type_scan {
+       BTC_SCAN_FINISH = 0x0,
+       BTC_SCAN_START = 0x1,
+       BTC_SCAN_MAX
+};
+
+enum btc_notify_type_associate {
+       BTC_ASSOCIATE_FINISH = 0x0,
+       BTC_ASSOCIATE_START = 0x1,
+       BTC_ASSOCIATE_MAX
+};
+
+enum btc_notify_type_media_status {
+       BTC_MEDIA_DISCONNECT = 0x0,
+       BTC_MEDIA_CONNECT = 0x1,
+       BTC_MEDIA_MAX
+};
+
+enum btc_notify_type_special_packet {
+       BTC_PACKET_UNKNOWN = 0x0,
+       BTC_PACKET_DHCP = 0x1,
+       BTC_PACKET_ARP = 0x2,
+       BTC_PACKET_EAPOL = 0x3,
+       BTC_PACKET_MAX
+};
+
+enum btc_notify_type_stack_operation {
+       BTC_STACK_OP_NONE = 0x0,
+       BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1,
+       BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2,
+       BTC_STACK_OP_MAX
+};
+
+
+typedef u8 (*bfp_btc_r1)(void *btc_context, u32 reg_addr);
+
+typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr);
+
+typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr);
+
+typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u8 data);
+
+typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr,
+                                  u32 bit_mask, u8 data1b);
+
+typedef void (*bfp_btc_w2)(void *btc_context, u32 reg_addr, u16 data);
+
+typedef void (*bfp_btc_w4)(void *btc_context, u32 reg_addr, u32 data);
+
+typedef void (*bfp_btc_wr_1byte_bit_mask)(void *btc_context, u32 reg_addr,
+                                         u8 bit_mask, u8 data);
+
+typedef void (*bfp_btc_set_bb_reg)(void *btc_context, u32 reg_addr,
+                                  u32 bit_mask, u32 data);
+
+typedef u32 (*bfp_btc_get_bb_reg)(void *btc_context, u32 reg_addr,
+                                 u32 bit_mask);
+
+typedef void (*bfp_btc_set_rf_reg)(void *btc_context, u8 rf_path, u32 reg_addr,
+                                  u32 bit_mask, u32 data);
+
+typedef u32 (*bfp_btc_get_rf_reg)(void *btc_context, u8 rf_path,
+                                 u32 reg_addr, u32 bit_mask);
+
+typedef void (*bfp_btc_fill_h2c)(void *btc_context, u8 element_id,
+                                u32 cmd_len, u8 *cmd_buffer);
+
+typedef        bool (*bfp_btc_get)(void *btcoexist, u8 get_type, void *out_buf);
+
+typedef        bool (*bfp_btc_set)(void *btcoexist, u8 set_type, void *in_buf);
+
+typedef void (*bfp_btc_disp_dbg_msg)(void *btcoexist, u8 disp_type);
+
+struct btc_bt_info {
+       bool bt_disabled;
+       u8 rssi_adjust_for_agc_table_on;
+       u8 rssi_adjust_for_1ant_coex_type;
+       bool bt_busy;
+       u8 agg_buf_size;
+       bool limited_dig;
+       bool reject_agg_pkt;
+       bool b_bt_ctrl_buf_size;
+       bool increase_scan_dev_num;
+       u16 bt_hci_ver;
+       u16 bt_real_fw_ver;
+       u8 bt_fw_ver;
+
+       /* the following is for 1Ant solution */
+       bool bt_ctrl_lps;
+       bool bt_pwr_save_mode;
+       bool bt_lps_on;
+       bool force_to_roam;
+       u8 force_exec_pwr_cmd_cnt;
+       u8 lps_1ant;
+       u8 rpwm_1ant;
+       u32 ra_mask;
+};
+
+struct btc_stack_info {
+       bool profile_notified;
+       u16 hci_version;        /* stack hci version */
+       u8 num_of_link;
+       bool bt_link_exist;
+       bool sco_exist;
+       bool acl_exist;
+       bool a2dp_exist;
+       bool hid_exist;
+       u8 num_of_hid;
+       bool pan_exist;
+       bool unknown_acl_exist;
+       char min_bt_rssi;
+};
+
+struct btc_statistics {
+       u32 cnt_bind;
+       u32 cnt_init_hw_config;
+       u32 cnt_init_coex_dm;
+       u32 cnt_ips_notify;
+       u32 cnt_lps_notify;
+       u32 cnt_scan_notify;
+       u32 cnt_connect_notify;
+       u32 cnt_media_status_notify;
+       u32 cnt_special_packet_notify;
+       u32 cnt_bt_info_notify;
+       u32 cnt_periodical;
+       u32 cnt_stack_operation_notify;
+       u32 cnt_dbg_ctrl;
+};
+
+struct btc_bt_link_info {
+       bool bt_link_exist;
+       bool sco_exist;
+       bool sco_only;
+       bool a2dp_exist;
+       bool a2dp_only;
+       bool hid_exist;
+       bool hid_only;
+       bool pan_exist;
+       bool pan_only;
+};
+
+enum btc_antenna_pos {
+       BTC_ANTENNA_AT_MAIN_PORT = 0x1,
+       BTC_ANTENNA_AT_AUX_PORT = 0x2,
+};
+
+struct btc_coexist {
+       /* make sure only one adapter can bind the data context  */
+       bool binded;
+       /* default adapter */
+       void *adapter;
+       struct btc_board_info board_info;
+       /* some bt info referenced by non-bt module */
+       struct btc_bt_info bt_info;
+       struct btc_stack_info stack_info;
+       enum btc_chip_interface chip_interface;
+       struct btc_bt_link_info bt_link_info;
+
+       bool initilized;
+       bool stop_coex_dm;
+       bool manual_control;
+       u8 *cli_buf;
+       struct btc_statistics statistics;
+       u8 pwr_mode_val[10];
+
+       /* function pointers - io related */
+       bfp_btc_r1 btc_read_1byte;
+       bfp_btc_w1 btc_write_1byte;
+       bfp_btc_w1_bit_mak btc_write_1byte_bitmask;
+       bfp_btc_r2 btc_read_2byte;
+       bfp_btc_w2 btc_write_2byte;
+       bfp_btc_r4 btc_read_4byte;
+       bfp_btc_w4 btc_write_4byte;
+
+       bfp_btc_set_bb_reg btc_set_bb_reg;
+       bfp_btc_get_bb_reg btc_get_bb_reg;
+
+
+       bfp_btc_set_rf_reg btc_set_rf_reg;
+       bfp_btc_get_rf_reg btc_get_rf_reg;
+
+       bfp_btc_fill_h2c btc_fill_h2c;
+
+       bfp_btc_disp_dbg_msg btc_disp_dbg_msg;
+
+       bfp_btc_get btc_get;
+       bfp_btc_set btc_set;
+};
+
+bool halbtc_is_wifi_uplink(struct rtl_priv *adapter);
+
+extern struct btc_coexist gl_bt_coexist;
+
+bool exhalbtc_initlize_variables(struct rtl_priv *adapter);
+void exhalbtc_init_hw_config(struct btc_coexist *btcoexist);
+void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist);
+void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action);
+void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
+                                enum _RT_MEDIA_STATUS media_status);
+void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
+void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
+                            u8 length);
+void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type);
+void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
+void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
+void exhalbtc_periodical(struct btc_coexist *btcoexist);
+void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len,
+                         u8 *data);
+void exhalbtc_stack_update_profile_info(void);
+void exhalbtc_set_hci_version(u16 hci_version);
+void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version);
+void exhalbtc_update_min_bt_rssi(char bt_rssi);
+void exhalbtc_set_bt_exist(bool bt_exist);
+void exhalbtc_set_chip_type(u8 chip_type);
+void exhalbtc_set_ant_num(u8 type, u8 ant_num);
+void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist);
+void exhalbtc_signal_compensation(struct btc_coexist *btcoexist,
+                                 u8 *rssi_wifi, u8 *rssi_bt);
+void exhalbtc_lps_leave(struct btc_coexist *btcoexist);
+void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
new file mode 100644 (file)
index 0000000..0ab94fe
--- /dev/null
@@ -0,0 +1,218 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "rtl_btc.h"
+#include "halbt_precomp.h"
+
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+static struct rtl_btc_ops rtl_btc_operation = {
+       .btc_init_variables = rtl_btc_init_variables,
+       .btc_init_hal_vars = rtl_btc_init_hal_vars,
+       .btc_init_hw_config = rtl_btc_init_hw_config,
+       .btc_ips_notify = rtl_btc_ips_notify,
+       .btc_scan_notify = rtl_btc_scan_notify,
+       .btc_connect_notify = rtl_btc_connect_notify,
+       .btc_mediastatus_notify = rtl_btc_mediastatus_notify,
+       .btc_periodical = rtl_btc_periodical,
+       .btc_halt_notify = rtl_btc_halt_notify,
+       .btc_btinfo_notify = rtl_btc_btinfo_notify,
+       .btc_is_limited_dig = rtl_btc_is_limited_dig,
+       .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
+       .btc_is_bt_disabled = rtl_btc_is_bt_disabled,
+};
+
+void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
+{
+       exhalbtc_initlize_variables(rtlpriv);
+}
+
+void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv)
+{
+       u8 ant_num;
+       u8 bt_exist;
+       u8 bt_type;
+
+       ant_num = rtl_get_hwpg_ant_num(rtlpriv);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                "%s, antNum is %d\n", __func__, ant_num);
+
+       bt_exist = rtl_get_hwpg_bt_exist(rtlpriv);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                "%s, bt_exist is %d\n", __func__, bt_exist);
+       exhalbtc_set_bt_exist(bt_exist);
+
+       bt_type = rtl_get_hwpg_bt_type(rtlpriv);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%s, bt_type is %d\n",
+                __func__, bt_type);
+       exhalbtc_set_chip_type(bt_type);
+
+       exhalbtc_set_ant_num(BT_COEX_ANT_TYPE_PG, ant_num);
+}
+
+void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv)
+{
+       exhalbtc_init_hw_config(&gl_bt_coexist);
+       exhalbtc_init_coex_dm(&gl_bt_coexist);
+}
+
+void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
+{
+       exhalbtc_ips_notify(&gl_bt_coexist, type);
+}
+
+void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
+{
+       exhalbtc_scan_notify(&gl_bt_coexist, scantype);
+}
+
+void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action)
+{
+       exhalbtc_connect_notify(&gl_bt_coexist, action);
+}
+
+void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
+                               enum _RT_MEDIA_STATUS mstatus)
+{
+       exhalbtc_mediastatus_notify(&gl_bt_coexist, mstatus);
+}
+
+void rtl_btc_periodical(struct rtl_priv *rtlpriv)
+{
+       exhalbtc_periodical(&gl_bt_coexist);
+}
+
+void rtl_btc_halt_notify(void)
+{
+       exhalbtc_halt_notify(&gl_bt_coexist);
+}
+
+void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
+{
+       exhalbtc_bt_info_notify(&gl_bt_coexist, tmp_buf, length);
+}
+
+bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv)
+{
+       return gl_bt_coexist.bt_info.limited_dig;
+}
+
+bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv)
+{
+       bool bt_change_edca = false;
+       u32 cur_edca_val;
+       u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b;
+       u32 edca_hs;
+       u32 edca_addr = 0x504;
+
+       cur_edca_val = rtl_read_dword(rtlpriv, edca_addr);
+       if (halbtc_is_wifi_uplink(rtlpriv)) {
+               if (cur_edca_val != edca_bt_hs_uplink) {
+                       edca_hs = edca_bt_hs_uplink;
+                       bt_change_edca = true;
+               }
+       } else {
+               if (cur_edca_val != edca_bt_hs_downlink) {
+                       edca_hs = edca_bt_hs_downlink;
+                       bt_change_edca = true;
+               }
+       }
+
+       if (bt_change_edca)
+               rtl_write_dword(rtlpriv, edca_addr, edca_hs);
+
+       return true;
+}
+
+bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv)
+{
+       if (gl_bt_coexist.bt_info.bt_disabled)
+               return true;
+       else
+               return false;
+}
+
+struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
+{
+       return &rtl_btc_operation;
+}
+EXPORT_SYMBOL(rtl_btc_get_ops_pointer);
+
+u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
+{
+       u8 num;
+
+       if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2)
+               num = 2;
+       else
+               num = 1;
+
+       return num;
+}
+
+enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       enum _RT_MEDIA_STATUS    m_status = RT_MEDIA_DISCONNECT;
+
+       u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
+
+       if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED)
+               m_status = RT_MEDIA_CONNECT;
+
+       return m_status;
+}
+
+u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv)
+{
+       return rtlpriv->btcoexist.btc_info.btcoexist;
+}
+
+u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv)
+{
+       return rtlpriv->btcoexist.btc_info.bt_type;
+}
+
+MODULE_AUTHOR("Page He <page_he@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
+
+static int __init rtl_btcoexist_module_init(void)
+{
+       return 0;
+}
+
+static void __exit rtl_btcoexist_module_exit(void)
+{
+       return;
+}
+
+module_init(rtl_btcoexist_module_init);
+module_exit(rtl_btcoexist_module_exit);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
new file mode 100644 (file)
index 0000000..805b22c
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_BTC_H__
+#define __RTL_BTC_H__
+
+#include "halbt_precomp.h"
+
+void rtl_btc_init_variables(struct rtl_priv *rtlpriv);
+void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv);
+void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv);
+void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type);
+void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype);
+void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action);
+void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
+                               enum _RT_MEDIA_STATUS mstatus);
+void rtl_btc_periodical(struct rtl_priv *rtlpriv);
+void rtl_btc_halt_notify(void);
+void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length);
+bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv);
+bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv);
+bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv);
+
+struct rtl_btc_ops *rtl_btc_get_ops_pointer(void);
+
+u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv);
+u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv);
+u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv);
+enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw);
+
+#endif
index 2d337a0c3df027c86742af4367c0c00fe64d2f49..ded691f76f2fb433060b71e9865fd953f93ef46f 100644 (file)
 
 #include <linux/export.h>
 
+void rtl_addr_delay(u32 addr)
+{
+       if (addr == 0xfe)
+               mdelay(50);
+       else if (addr == 0xfd)
+               mdelay(5);
+       else if (addr == 0xfc)
+               mdelay(1);
+       else if (addr == 0xfb)
+               udelay(50);
+       else if (addr == 0xfa)
+               udelay(5);
+       else if (addr == 0xf9)
+               udelay(1);
+}
+EXPORT_SYMBOL(rtl_addr_delay);
+
+void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr,
+                    u32 mask, u32 data)
+{
+       if (addr == 0xfe) {
+               mdelay(50);
+       } else if (addr == 0xfd) {
+               mdelay(5);
+       } else if (addr == 0xfc) {
+               mdelay(1);
+       } else if (addr == 0xfb) {
+               udelay(50);
+       } else if (addr == 0xfa) {
+               udelay(5);
+       } else if (addr == 0xf9) {
+               udelay(1);
+       } else {
+               rtl_set_rfreg(hw, rfpath, addr, mask, data);
+               udelay(1);
+       }
+}
+EXPORT_SYMBOL(rtl_rfreg_delay);
+
+void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data)
+{
+       if (addr == 0xfe) {
+               mdelay(50);
+       } else if (addr == 0xfd) {
+               mdelay(5);
+       } else if (addr == 0xfc) {
+               mdelay(1);
+       } else if (addr == 0xfb) {
+               udelay(50);
+       } else if (addr == 0xfa) {
+               udelay(5);
+       } else if (addr == 0xf9) {
+               udelay(1);
+       } else {
+               rtl_set_bbreg(hw, addr, MASKDWORD, data);
+               udelay(1);
+       }
+}
+EXPORT_SYMBOL(rtl_bb_delay);
+
 void rtl_fw_cb(const struct firmware *firmware, void *context)
 {
        struct ieee80211_hw *hw = context;
@@ -475,20 +535,40 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u32 rx_conf;
 
        *new_flags &= RTL_SUPPORTED_FILTERS;
        if (!changed_flags)
                return;
 
+       /* if ssid not set to hw don't check bssid
+        * here just used for linked scanning, & linked
+        * and nolink check bssid is set in set network_type */
+       if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
+               (mac->link_state >= MAC80211_LINKED)) {
+               if (mac->opmode != NL80211_IFTYPE_AP &&
+                   mac->opmode != NL80211_IFTYPE_MESH_POINT) {
+                       if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
+                               rtlpriv->cfg->ops->set_chk_bssid(hw, false);
+                       } else {
+                               rtlpriv->cfg->ops->set_chk_bssid(hw, true);
+                       }
+               }
+       }
+
+       /* must be called after set_chk_bssid since that function modifies the
+        * RCR register too. */
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf));
+
        /*TODO: we disable broadcase now, so enable here */
        if (changed_flags & FIF_ALLMULTI) {
                if (*new_flags & FIF_ALLMULTI) {
-                       mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
+                       rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
                            rtlpriv->cfg->maps[MAC_RCR_AB];
                        RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
                                 "Enable receive multicast frame\n");
                } else {
-                       mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
+                       rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
                                          rtlpriv->cfg->maps[MAC_RCR_AB]);
                        RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
                                 "Disable receive multicast frame\n");
@@ -497,39 +577,25 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
 
        if (changed_flags & FIF_FCSFAIL) {
                if (*new_flags & FIF_FCSFAIL) {
-                       mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+                       rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
                        RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
                                 "Enable receive FCS error frame\n");
                } else {
-                       mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+                       rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
                        RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
                                 "Disable receive FCS error frame\n");
                }
        }
 
-       /* if ssid not set to hw don't check bssid
-        * here just used for linked scanning, & linked
-        * and nolink check bssid is set in set network_type */
-       if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
-               (mac->link_state >= MAC80211_LINKED)) {
-               if (mac->opmode != NL80211_IFTYPE_AP &&
-                   mac->opmode != NL80211_IFTYPE_MESH_POINT) {
-                       if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
-                               rtlpriv->cfg->ops->set_chk_bssid(hw, false);
-                       } else {
-                               rtlpriv->cfg->ops->set_chk_bssid(hw, true);
-                       }
-               }
-       }
 
        if (changed_flags & FIF_CONTROL) {
                if (*new_flags & FIF_CONTROL) {
-                       mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
+                       rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
 
                        RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
                                 "Enable receive control frame\n");
                } else {
-                       mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
+                       rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
                        RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
                                 "Disable receive control frame\n");
                }
@@ -537,15 +603,17 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
 
        if (changed_flags & FIF_OTHER_BSS) {
                if (*new_flags & FIF_OTHER_BSS) {
-                       mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
+                       rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
                        RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
                                 "Enable receive other BSS's frame\n");
                } else {
-                       mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
+                       rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
                        RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
                                 "Disable receive other BSS's frame\n");
                }
        }
+
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf));
 }
 static int rtl_op_sta_add(struct ieee80211_hw *hw,
                         struct ieee80211_vif *vif,
@@ -738,6 +806,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
                                rtlpriv->cfg->ops->linked_set_reg(hw);
                        rcu_read_lock();
                        sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
+                       if (!sta) {
+                               pr_err("ieee80211_find_sta returned NULL\n");
+                               rcu_read_unlock();
+                               goto out;
+                       }
 
                        if (vif->type == NL80211_IFTYPE_STATION && sta)
                                rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
@@ -892,7 +965,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 
                        mac->basic_rates = basic_rates;
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
-                                       (u8 *) (&basic_rates));
+                                       (u8 *)(&basic_rates));
                }
                rcu_read_unlock();
        }
@@ -906,6 +979,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
                if (bss_conf->assoc) {
                        if (ppsc->fwctrl_lps) {
                                u8 mstatus = RT_MEDIA_CONNECT;
+                               u8 keep_alive = 10;
+                               rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                HW_VAR_KEEP_ALIVE,
+                                                (u8 *)(&keep_alive));
+
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                                      HW_VAR_H2C_FW_JOINBSSRPT,
                                                      &mstatus);
index 2fe46a1b4f1f12c3e77ba985d59c4aaff1d88357..027e75374dcc9467c4b01040060d6defaa6d6f55 100644 (file)
@@ -41,5 +41,9 @@
 
 extern const struct ieee80211_ops rtl_ops;
 void rtl_fw_cb(const struct firmware *firmware, void *context);
+void rtl_addr_delay(u32 addr);
+void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr,
+                    u32 mask, u32 data);
+void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data);
 
 #endif
index d7aa165fe6776cb64e178f3ec6db0eeb7e9c255c..f26f4ffc771db688f5e69c6d148a034bdef47da0 100644 (file)
@@ -811,19 +811,19 @@ done:
                if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
                        return;
                tmp_one = 1;
-               rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
                                            HW_DESC_RXBUFF_ADDR,
                                            (u8 *)&bufferaddress);
-               rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
                                            HW_DESC_RXPKT_LEN,
                                            (u8 *)&rtlpci->rxbuffersize);
 
                if (index == rtlpci->rxringcount - 1)
-                       rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
+                       rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
                                                    HW_DESC_RXERO,
                                                    &tmp_one);
 
-               rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXOWN,
                                            &tmp_one);
 
                index = (index + 1) % rtlpci->rxringcount;
@@ -983,6 +983,8 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        struct sk_buff *pskb = NULL;
        struct rtl_tx_desc *pdesc = NULL;
        struct rtl_tcb_desc tcb_desc;
+       /*This is for new trx flow*/
+       struct rtl_tx_buffer_desc *pbuffer_desc = NULL;
        u8 temp_one = 1;
 
        memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
@@ -1004,11 +1006,12 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        info = IEEE80211_SKB_CB(pskb);
        pdesc = &ring->desc[0];
        rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
-               info, NULL, pskb, BEACON_QUEUE, &tcb_desc);
+                                       (u8 *)pbuffer_desc, info, NULL, pskb,
+                                       BEACON_QUEUE, &tcb_desc);
 
        __skb_queue_tail(&ring->queue, pskb);
 
-       rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, HW_DESC_OWN,
+       rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN,
                                    &temp_one);
 
        return;
@@ -1066,7 +1069,7 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
        mac->current_ampdu_factor = 3;
 
        /*QOS*/
-       rtlpci->acm_method = eAcmWay2_SW;
+       rtlpci->acm_method = EACMWAY2_SW;
 
        /*task */
        tasklet_init(&rtlpriv->works.irq_tasklet,
@@ -1113,7 +1116,7 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
                                              ((i + 1) % entries) *
                                              sizeof(*ring);
 
-               rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]),
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)&(ring[i]),
                                            true, HW_DESC_TX_NEXTDESC_ADDR,
                                            (u8 *)&nextdescaddress);
        }
@@ -1188,19 +1191,19 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
                                dev_kfree_skb_any(skb);
                                return 1;
                        }
-                       rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
+                       rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
                                                    HW_DESC_RXBUFF_ADDR,
                                                    (u8 *)&bufferaddress);
-                       rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
+                       rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
                                                    HW_DESC_RXPKT_LEN,
                                                    (u8 *)&rtlpci->
                                                    rxbuffersize);
-                       rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
+                       rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
                                                    HW_DESC_RXOWN,
                                                    &tmp_one);
                }
 
-               rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
                                            HW_DESC_RXERO, &tmp_one);
        }
        return 0;
@@ -1331,7 +1334,7 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
 
                        for (i = 0; i < rtlpci->rxringcount; i++) {
                                entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
-                               rtlpriv->cfg->ops->set_desc((u8 *) entry,
+                               rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry,
                                                            false,
                                                            HW_DESC_RXOWN,
                                                            &tmp_one);
@@ -1424,6 +1427,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct rtl8192_tx_ring *ring;
        struct rtl_tx_desc *pdesc;
+       struct rtl_tx_buffer_desc *ptx_bd_desc = NULL;
        u8 idx;
        u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb);
        unsigned long flags;
@@ -1464,17 +1468,22 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
                idx = 0;
 
        pdesc = &ring->desc[idx];
-       own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
-                       true, HW_DESC_OWN);
+       if (rtlpriv->use_new_trx_flow) {
+               ptx_bd_desc = &ring->buffer_desc[idx];
+       } else {
+               own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc,
+                               true, HW_DESC_OWN);
 
-       if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-                        "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
-                        hw_queue, ring->idx, idx,
-                        skb_queue_len(&ring->queue));
+               if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+                                hw_queue, ring->idx, idx,
+                                skb_queue_len(&ring->queue));
 
-               spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-               return skb->len;
+                       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+                                              flags);
+                       return skb->len;
+               }
        }
 
        if (ieee80211_is_data_qos(fc)) {
@@ -1494,17 +1503,20 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
                rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
 
        rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
-                       info, sta, skb, hw_queue, ptcb_desc);
+                       (u8 *)ptx_bd_desc, info, sta, skb, hw_queue, ptcb_desc);
 
        __skb_queue_tail(&ring->queue, skb);
 
-       rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true,
-                                   HW_DESC_OWN, &temp_one);
-
+       if (rtlpriv->use_new_trx_flow) {
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
+                                           HW_DESC_OWN, (u8 *)&hw_queue);
+       } else {
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
+                                           HW_DESC_OWN, (u8 *)&temp_one);
+       }
 
        if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
            hw_queue != BEACON_QUEUE) {
-
                RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
                         "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
                         hw_queue, ring->idx, idx,
index d3262ec45d230f0f8abd1744501a004006c48198..90174a814a6d26fc6e384171afc54324b98a0abd 100644 (file)
@@ -137,12 +137,22 @@ struct rtl_tx_cmd_desc {
        u32 dword[16];
 } __packed;
 
+/* In new TRX flow, Buffer_desc is new concept
+ * But TX wifi info == TX descriptor in old flow
+ * RX wifi info == RX descriptor in old flow
+ */
+struct rtl_tx_buffer_desc {
+       u32 dword[8]; /*seg = 4*/
+} __packed;
+
 struct rtl8192_tx_ring {
        struct rtl_tx_desc *desc;
        dma_addr_t dma;
        unsigned int idx;
        unsigned int entries;
        struct sk_buff_head queue;
+       /*add for new trx flow*/
+       struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/
 };
 
 struct rtl8192_rx_ring {
@@ -199,6 +209,10 @@ struct rtl_pci {
 
        u16 shortretry_limit;
        u16 longretry_limit;
+
+       /* MSI support */
+       bool msi_support;
+       bool using_msi;
 };
 
 struct mp_adapter {
index d1c0191a195b909e5095fde8807eb671b307e374..de7f05f848ef47ddaf3c18a1e727a7cbb401b1db 100644 (file)
 #include "base.h"
 #include "ps.h"
 
+/*     Description:
+ *             This routine deals with the Power Configuration CMD
+ *              parsing for RTL8723/RTL8188E Series IC.
+ *     Assumption:
+ *             We should follow specific format that was released from HW SD.
+ */
+bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+                             u8 faversion, u8 interface_type,
+                             struct wlan_pwr_cfg pwrcfgcmd[])
+{
+       struct wlan_pwr_cfg cfg_cmd = {0};
+       bool polling_bit = false;
+       u32 ary_idx = 0;
+       u8 value = 0;
+       u32 offset = 0;
+       u32 polling_count = 0;
+       u32 max_polling_cnt = 5000;
+
+       do {
+               cfg_cmd = pwrcfgcmd[ary_idx];
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                       "rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), famsk(%#x),"
+                       "interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n",
+                       GET_PWR_CFG_OFFSET(cfg_cmd),
+                                          GET_PWR_CFG_CUT_MASK(cfg_cmd),
+                       GET_PWR_CFG_FAB_MASK(cfg_cmd),
+                                            GET_PWR_CFG_INTF_MASK(cfg_cmd),
+                       GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd),
+                       GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd));
+
+               if ((GET_PWR_CFG_FAB_MASK(cfg_cmd)&faversion) &&
+                   (GET_PWR_CFG_CUT_MASK(cfg_cmd)&cut_version) &&
+                   (GET_PWR_CFG_INTF_MASK(cfg_cmd)&interface_type)) {
+                       switch (GET_PWR_CFG_CMD(cfg_cmd)) {
+                       case PWR_CMD_READ:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                       "rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n");
+                               break;
+                       case PWR_CMD_WRITE:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                       "rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n");
+                               offset = GET_PWR_CFG_OFFSET(cfg_cmd);
+
+                               /*Read the value from system register*/
+                               value = rtl_read_byte(rtlpriv, offset);
+                               value &= (~(GET_PWR_CFG_MASK(cfg_cmd)));
+                               value |= (GET_PWR_CFG_VALUE(cfg_cmd) &
+                                         GET_PWR_CFG_MASK(cfg_cmd));
+
+                               /*Write the value back to sytem register*/
+                               rtl_write_byte(rtlpriv, offset, value);
+                               break;
+                       case PWR_CMD_POLLING:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                       "rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n");
+                               polling_bit = false;
+                               offset = GET_PWR_CFG_OFFSET(cfg_cmd);
+
+                               do {
+                                       value = rtl_read_byte(rtlpriv, offset);
+
+                                       value &= GET_PWR_CFG_MASK(cfg_cmd);
+                                       if (value ==
+                                           (GET_PWR_CFG_VALUE(cfg_cmd)
+                                           & GET_PWR_CFG_MASK(cfg_cmd)))
+                                               polling_bit = true;
+                                       else
+                                               udelay(10);
+
+                                       if (polling_count++ > max_polling_cnt)
+                                               return false;
+                               } while (!polling_bit);
+                               break;
+                       case PWR_CMD_DELAY:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                       "rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n");
+                               if (GET_PWR_CFG_VALUE(cfg_cmd) ==
+                                   PWRSEQ_DELAY_US)
+                                       udelay(GET_PWR_CFG_OFFSET(cfg_cmd));
+                               else
+                                       mdelay(GET_PWR_CFG_OFFSET(cfg_cmd));
+                               break;
+                       case PWR_CMD_END:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                        "rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n");
+                               return true;
+                       default:
+                               RT_ASSERT(false,
+                                        "rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n");
+                               break;
+                       }
+
+               }
+               ary_idx++;
+       } while (1);
+
+       return true;
+}
+EXPORT_SYMBOL(rtl_hal_pwrseqcmdparsing);
+
 bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
index 88bd76ea88f7621dd92cb4ff495ee22e9dc53912..3bd41f958974308e6b9a3b25a9670541cd3f56eb 100644 (file)
 
 #define MAX_SW_LPS_SLEEP_INTV  5
 
+/*---------------------------------------------
+ * 3 The value of cmd: 4 bits
+ *---------------------------------------------
+ */
+#define    PWR_CMD_READ                0x00
+#define    PWR_CMD_WRITE       0x01
+#define    PWR_CMD_POLLING     0x02
+#define    PWR_CMD_DELAY       0x03
+#define    PWR_CMD_END         0x04
+
+/* define the base address of each block */
+#define        PWR_BASEADDR_MAC        0x00
+#define        PWR_BASEADDR_USB        0x01
+#define        PWR_BASEADDR_PCIE       0x02
+#define        PWR_BASEADDR_SDIO       0x03
+
+#define        PWR_FAB_ALL_MSK         (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+#define        PWR_CUT_TESTCHIP_MSK    BIT(0)
+#define        PWR_CUT_A_MSK           BIT(1)
+#define        PWR_CUT_B_MSK           BIT(2)
+#define        PWR_CUT_C_MSK           BIT(3)
+#define        PWR_CUT_D_MSK           BIT(4)
+#define        PWR_CUT_E_MSK           BIT(5)
+#define        PWR_CUT_F_MSK           BIT(6)
+#define        PWR_CUT_G_MSK           BIT(7)
+#define        PWR_CUT_ALL_MSK         0xFF
+#define PWR_INTF_SDIO_MSK      BIT(0)
+#define PWR_INTF_USB_MSK       BIT(1)
+#define PWR_INTF_PCI_MSK       BIT(2)
+#define PWR_INTF_ALL_MSK       (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+enum pwrseq_delay_unit {
+       PWRSEQ_DELAY_US,
+       PWRSEQ_DELAY_MS,
+};
+
+struct wlan_pwr_cfg {
+       u16 offset;
+       u8 cut_msk;
+       u8 fab_msk:4;
+       u8 interface_msk:4;
+       u8 base:4;
+       u8 cmd:4;
+       u8 msk;
+       u8 value;
+};
+
+#define        GET_PWR_CFG_OFFSET(__PWR_CMD)   (__PWR_CMD.offset)
+#define        GET_PWR_CFG_CUT_MASK(__PWR_CMD) (__PWR_CMD.cut_msk)
+#define        GET_PWR_CFG_FAB_MASK(__PWR_CMD) (__PWR_CMD.fab_msk)
+#define        GET_PWR_CFG_INTF_MASK(__PWR_CMD)        (__PWR_CMD.interface_msk)
+#define        GET_PWR_CFG_BASE(__PWR_CMD)     (__PWR_CMD.base)
+#define        GET_PWR_CFG_CMD(__PWR_CMD)      (__PWR_CMD.cmd)
+#define        GET_PWR_CFG_MASK(__PWR_CMD)     (__PWR_CMD.msk)
+#define        GET_PWR_CFG_VALUE(__PWR_CMD)    (__PWR_CMD.value)
+
+bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+                             u8 fab_version, u8 interface_type,
+                             struct wlan_pwr_cfg pwrcfgcmd[]);
+
 bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
                         enum rf_pwrstate state_toset, u32 changesource);
 bool rtl_ps_enable_nic(struct ieee80211_hw *hw);
index 5b194e97f4b3947e4a4af5c0b057c9b4689f87da..a85419a37651fcdb372607acefdb22b0f690fb31 100644 (file)
@@ -5,7 +5,6 @@ rtl8188ee-objs :=               \
                led.o           \
                phy.o           \
                pwrseq.o        \
-               pwrseqcmd.o     \
                rf.o            \
                sw.o            \
                table.o         \
index a6184b6e1d57ff50bca6a4f4aa16ac2871dc295f..97bc9aa5e1d1c42cc1abaff03bf87c16ada8ac5f 100644 (file)
@@ -235,7 +235,7 @@ void rtl88e_dm_txpower_track_adjust(struct ieee80211_hw *hw,
        u8 pwr_val = 0;
        u8 cck_base = rtldm->swing_idx_cck_base;
        u8 cck_val = rtldm->swing_idx_cck;
-       u8 ofdm_base = rtldm->swing_idx_ofdm_base;
+       u8 ofdm_base = rtldm->swing_idx_ofdm_base[0];
        u8 ofdm_val = rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A];
 
        if (type == 0) {
@@ -726,7 +726,7 @@ static void rtl88e_dm_pwdb_monitor(struct ieee80211_hw *hw)
        static u64 last_rx;
        long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
 
-       if (rtlhal->oem_id == RT_CID_819x_HP) {
+       if (rtlhal->oem_id == RT_CID_819X_HP) {
                u64 cur_txok_cnt = 0;
                u64 cur_rxok_cnt = 0;
                cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok;
@@ -912,7 +912,7 @@ static void rtl88e_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
        for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
                if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
                        ofdm_old[0] = (u8) i;
-                       rtldm->swing_idx_ofdm_base = (u8)i;
+                       rtldm->swing_idx_ofdm_base[0] = (u8)i;
                        RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
                                 "Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index = 0x%x\n",
                                 ROFDM0_XATXIQIMBAL,
index e06971be7df77e047e8d869d046a126d0e987d14..bd2a26bafb695c750b47d4d164a7f357e3ee9488 100644 (file)
@@ -41,7 +41,6 @@
 #include "fw.h"
 #include "led.h"
 #include "hw.h"
-#include "pwrseqcmd.h"
 #include "pwrseq.h"
 
 #define LLT_CONFIG             5
@@ -509,7 +508,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                u8 e_aci = *((u8 *)val);
                rtl88e_dm_init_edca_turbo(hw);
 
-               if (rtlpci->acm_method != eAcmWay2_SW)
+               if (rtlpci->acm_method != EACMWAY2_SW)
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
                                                      (u8 *)(&e_aci));
                break; }
@@ -815,11 +814,11 @@ static bool _rtl88ee_init_mac(struct ieee80211_hw *hw)
 
        rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
        /* HW Power on sequence */
-       if (!rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
-                                       PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
-                                       Rtl8188E_NIC_ENABLE_FLOW)) {
+       if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
+                                     PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
+                                     Rtl8188E_NIC_ENABLE_FLOW)) {
                RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-                        "init MAC Fail as rtl88_hal_pwrseqcmdparsing\n");
+                        "init MAC Fail as rtl_hal_pwrseqcmdparsing\n");
                return false;
        }
 
@@ -1025,9 +1024,20 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
        bool rtstatus = true;
        int err = 0;
        u8 tmp_u1b, u1byte;
+       unsigned long flags;
 
        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Rtl8188EE hw init\n");
        rtlpriv->rtlhal.being_init_adapter = true;
+       /* As this function can take a very long time (up to 350 ms)
+        * and can be called with irqs disabled, reenable the irqs
+        * to let the other devices continue being serviced.
+        *
+        * It is safe doing so since our own interrupts will only be enabled
+        * in a subsequent step.
+        */
+       local_save_flags(flags);
+       local_irq_enable();
+
        rtlpriv->intf_ops->disable_aspm(hw);
 
        tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CLKR+1);
@@ -1043,7 +1053,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
        if (rtstatus != true) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
                err = 1;
-               return err;
+               goto exit;
        }
 
        err = rtl88e_download_fw(hw, false);
@@ -1051,8 +1061,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         "Failed to download FW. Init HW without FW now..\n");
                err = 1;
-               rtlhal->fw_ready = false;
-               return err;
+               goto exit;
        } else {
                rtlhal->fw_ready = true;
        }
@@ -1097,7 +1106,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
        if (ppsc->rfpwr_state == ERFON) {
                if ((rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) ||
                    ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) &&
-                   (rtlhal->oem_id == RT_CID_819x_HP))) {
+                   (rtlhal->oem_id == RT_CID_819X_HP))) {
                        rtl88e_phy_set_rfpath_switch(hw, true);
                        rtlpriv->dm.fat_table.rx_idle_ant = MAIN_ANT;
                } else {
@@ -1135,10 +1144,12 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
        }
        rtl_write_byte(rtlpriv, REG_NAV_CTRL+2,  ((30000+127)/128));
        rtl88e_dm_init(hw);
+exit:
+       local_irq_restore(flags);
        rtlpriv->rtlhal.being_init_adapter = false;
        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "end of Rtl8188EE hw init %x\n",
                 err);
-       return 0;
+       return err;
 }
 
 static enum version_8188e _rtl88ee_read_chip_version(struct ieee80211_hw *hw)
@@ -1235,12 +1246,13 @@ static int _rtl88ee_set_media_status(struct ieee80211_hw *hw,
 void rtl88ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       u32 reg_rcr = rtlpci->receive_config;
+       u32 reg_rcr;
 
        if (rtlpriv->psc.rfpwr_state != ERFON)
                return;
 
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
        if (check_bssid == true) {
                reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
@@ -1345,9 +1357,9 @@ static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw)
        }
        rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+1, 0xFF);
 
-       rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
-                                  PWR_INTF_PCI_MSK,
-                                  Rtl8188E_NIC_LPS_ENTER_FLOW);
+       rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+                                PWR_INTF_PCI_MSK,
+                                Rtl8188E_NIC_LPS_ENTER_FLOW);
 
        rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
 
@@ -1361,8 +1373,8 @@ static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw)
        u1b_tmp = rtl_read_byte(rtlpriv, REG_32K_CTRL);
        rtl_write_byte(rtlpriv, REG_32K_CTRL, (u1b_tmp & (~BIT(0))));
 
-       rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
-                                  PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW);
+       rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+                                PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW);
 
        u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
        rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(3))));
@@ -1872,15 +1884,15 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
                case EEPROM_CID_DEFAULT:
                        if (rtlefuse->eeprom_did == 0x8179) {
                                if (rtlefuse->eeprom_svid == 0x1025) {
-                                       rtlhal->oem_id = RT_CID_819x_Acer;
+                                       rtlhal->oem_id = RT_CID_819X_ACER;
                                } else if ((rtlefuse->eeprom_svid == 0x10EC &&
                                            rtlefuse->eeprom_smid == 0x0179) ||
                                            (rtlefuse->eeprom_svid == 0x17AA &&
                                            rtlefuse->eeprom_smid == 0x0179)) {
-                                       rtlhal->oem_id = RT_CID_819x_Lenovo;
+                                       rtlhal->oem_id = RT_CID_819X_LENOVO;
                                } else if (rtlefuse->eeprom_svid == 0x103c &&
                                         rtlefuse->eeprom_smid == 0x197d) {
-                                       rtlhal->oem_id = RT_CID_819x_HP;
+                                       rtlhal->oem_id = RT_CID_819X_HP;
                                } else {
                                        rtlhal->oem_id = RT_CID_DEFAULT;
                                }
@@ -1892,7 +1904,7 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
                        rtlhal->oem_id = RT_CID_TOSHIBA;
                        break;
                case EEPROM_CID_QMI:
-                       rtlhal->oem_id = RT_CID_819x_QMI;
+                       rtlhal->oem_id = RT_CID_819X_QMI;
                        break;
                case EEPROM_CID_WHQL:
                default:
@@ -1911,14 +1923,14 @@ static void _rtl88ee_hal_customized_behavior(struct ieee80211_hw *hw)
        pcipriv->ledctl.led_opendrain = true;
 
        switch (rtlhal->oem_id) {
-       case RT_CID_819x_HP:
+       case RT_CID_819X_HP:
                pcipriv->ledctl.led_opendrain = true;
                break;
-       case RT_CID_819x_Lenovo:
+       case RT_CID_819X_LENOVO:
        case RT_CID_DEFAULT:
        case RT_CID_TOSHIBA:
        case RT_CID_CCX:
-       case RT_CID_819x_Acer:
+       case RT_CID_819X_ACER:
        case RT_CID_WHQL:
        default:
                break;
index d67f9c731cc4600e57d774e7125d80c945e196b6..1cd6c16d597ee40a01e3b529ea4faca80f22c773 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "../wifi.h"
 #include "../pci.h"
+#include "../core.h"
 #include "../ps.h"
 #include "reg.h"
 #include "def.h"
@@ -151,18 +152,7 @@ static bool config_bb_with_pgheader(struct ieee80211_hw *hw,
                        v2 = table_pg[i + 1];
 
                        if (v1 < 0xcdcdcdcd) {
-                               if (table_pg[i] == 0xfe)
-                                       mdelay(50);
-                               else if (table_pg[i] == 0xfd)
-                                       mdelay(5);
-                               else if (table_pg[i] == 0xfc)
-                                       mdelay(1);
-                               else if (table_pg[i] == 0xfb)
-                                       udelay(50);
-                               else if (table_pg[i] == 0xfa)
-                                       udelay(5);
-                               else if (table_pg[i] == 0xf9)
-                                       udelay(1);
+                               rtl_addr_delay(table_pg[i]);
 
                                store_pwrindex_offset(hw, table_pg[i],
                                                      table_pg[i + 1],
@@ -672,24 +662,9 @@ static void _rtl8188e_config_rf_reg(struct ieee80211_hw *hw,
                                    u32 addr, u32 data, enum radio_path rfpath,
                                    u32 regaddr)
 {
-       if (addr == 0xffe) {
-               mdelay(50);
-       } else if (addr == 0xfd) {
-               mdelay(5);
-       } else if (addr == 0xfc) {
-               mdelay(1);
-       } else if (addr == 0xfb) {
-               udelay(50);
-       } else if (addr == 0xfa) {
-               udelay(5);
-       } else if (addr == 0xf9) {
-               udelay(1);
-       } else {
-               rtl_set_rfreg(hw, rfpath, regaddr,
-                             RFREG_OFFSET_MASK,
-                             data);
-               udelay(1);
-       }
+       rtl_rfreg_delay(hw, rfpath, regaddr,
+                       RFREG_OFFSET_MASK,
+                       data);
 }
 
 static void rtl88_config_s(struct ieee80211_hw *hw,
@@ -702,28 +677,6 @@ static void rtl88_config_s(struct ieee80211_hw *hw,
                                addr | maskforphyset);
 }
 
-static void _rtl8188e_config_bb_reg(struct ieee80211_hw *hw,
-                                   u32 addr, u32 data)
-{
-       if (addr == 0xfe) {
-               mdelay(50);
-       } else if (addr == 0xfd) {
-               mdelay(5);
-       } else if (addr == 0xfc) {
-               mdelay(1);
-       } else if (addr == 0xfb) {
-               udelay(50);
-       } else if (addr == 0xfa) {
-               udelay(5);
-       } else if (addr == 0xf9) {
-               udelay(1);
-       } else {
-               rtl_set_bbreg(hw, addr, MASKDWORD, data);
-               udelay(1);
-       }
-}
-
-
 #define NEXT_PAIR(v1, v2, i)                           \
        do {                                            \
                i += 2; v1 = array_table[i];            \
@@ -795,7 +748,7 @@ static void set_baseband_phy_config(struct ieee80211_hw *hw)
                v1 = array_table[i];
                v2 = array_table[i + 1];
                if (v1 < 0xcdcdcdcd) {
-                       _rtl8188e_config_bb_reg(hw, v1, v2);
+                       rtl_bb_delay(hw, v1, v2);
                } else {/*This line is the start line of branch.*/
                        if (!check_cond(hw, array_table[i])) {
                                /*Discard the following (offset, data) pairs*/
@@ -811,7 +764,7 @@ static void set_baseband_phy_config(struct ieee80211_hw *hw)
                                while (v2 != 0xDEAD &&
                                       v2 != 0xCDEF &&
                                       v2 != 0xCDCD && i < arraylen - 2) {
-                                       _rtl8188e_config_bb_reg(hw, v1, v2);
+                                       rtl_bb_delay(hw, v1, v2);
                                        NEXT_PAIR(v1, v2, i);
                                }
 
@@ -1002,7 +955,7 @@ bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
                        }
                }
 
-               if (rtlhal->oem_id == RT_CID_819x_HP)
+               if (rtlhal->oem_id == RT_CID_819X_HP)
                        rtl88_config_s(hw, 0x52, 0x7E4BD);
 
                break;
index 028ec6dd52b4920c7e8db9ad2c2a98e92f509c43..32e135ab9a63fcda64369ea3b0776c0e13175d68 100644 (file)
@@ -30,7 +30,6 @@
 #ifndef __RTL8723E_PWRSEQ_H__
 #define __RTL8723E_PWRSEQ_H__
 
-#include "pwrseqcmd.h"
 /*
        Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd
        There are 6 HW Power States:
index d849abf7d94a864980de709265b4af238773ba4f..7af85cfa8f8706f0c67c0bf2082d11889fa662d9 100644 (file)
 #define        BWORD1                                  0xc
 #define        BWORD                                   0xf
 
-#define        MASKBYTE0                               0xff
-#define        MASKBYTE1                               0xff00
-#define        MASKBYTE2                               0xff0000
-#define        MASKBYTE3                               0xff000000
-#define        MASKHWORD                               0xffff0000
-#define        MASKLWORD                               0x0000ffff
-#define        MASKDWORD                               0xffffffff
-#define        MASK12BITS                              0xfff
-#define        MASKH4BITS                              0xf0000000
-#define MASKOFDM_D                             0xffc00000
-#define        MASKCCK                                 0x3f3f3f3f
-
-#define        MASK4BITS                               0x0f
-#define        MASK20BITS                              0xfffff
-#define RFREG_OFFSET_MASK                      0xfffff
-
 #define        BENABLE                                 0x1
 #define        BDISABLE                                0x0
 
index 27ace3054d5686869a336ce020a91737ff71bc2e..2ba6f510d884cca149f7a7b9c06281c297593aa4 100644 (file)
@@ -489,9 +489,8 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
 
 void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
                          struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-                         struct ieee80211_tx_info *info,
-                         struct ieee80211_sta *sta,
-                         struct sk_buff *skb,
+                         u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+                         struct ieee80211_sta *sta, struct sk_buff *skb,
                          u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -734,7 +733,8 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw,
                      pdesc, TX_DESC_SIZE);
 }
 
-void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                     u8 desc_name, u8 *val)
 {
        if (istx == true) {
                switch (desc_name) {
index 21ca33a7c770b83e338bd735084d417444810efc..8c2609412d2cc26d92b7efcccf85ef0281def89d 100644 (file)
@@ -777,15 +777,15 @@ struct rx_desc_88e {
 
 void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
                          struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-                         struct ieee80211_tx_info *info,
-                         struct ieee80211_sta *sta,
-                         struct sk_buff *skb,
+                         u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+                         struct ieee80211_sta *sta, struct sk_buff *skb,
                          u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
 bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
                           struct rtl_stats *status,
                           struct ieee80211_rx_status *rx_status,
                           u8 *pdesc, struct sk_buff *skb);
-void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                     u8 desc_name, u8 *val);
 u32 rtl88ee_get_desc(u8 *pdesc, bool istx, u8 desc_name);
 void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
 void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
index 2eb0b38384dd7cef1323f5817be961954d31f514..4ae51d5b436fb156329f0fd269ad2339de81e6d4 100644 (file)
@@ -319,7 +319,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                        u8 e_aci = *(val);
                        rtl92c_dm_init_edca_turbo(hw);
 
-                       if (rtlpci->acm_method != eAcmWay2_SW)
+                       if (rtlpci->acm_method != EACMWAY2_SW)
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                                              HW_VAR_ACM_CTRL,
                                                              (&e_aci));
@@ -542,9 +542,11 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                                                (u8 *)(&fw_current_inps));
                        }
                break; }
+       case HW_VAR_KEEP_ALIVE:
+               break;
        default:
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "switch case not processed\n");
+                        "switch case %d not processed\n", variable);
                break;
        }
 }
@@ -1214,11 +1216,13 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
 void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+       u32 reg_rcr;
 
        if (rtlpriv->psc.rfpwr_state != ERFON)
                return;
 
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
        if (check_bssid) {
                reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
@@ -1734,7 +1738,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
                        if (rtlefuse->eeprom_did == 0x8176) {
                                if ((rtlefuse->eeprom_svid == 0x103C &&
                                     rtlefuse->eeprom_smid == 0x1629))
-                                       rtlhal->oem_id = RT_CID_819x_HP;
+                                       rtlhal->oem_id = RT_CID_819X_HP;
                                else
                                        rtlhal->oem_id = RT_CID_DEFAULT;
                        } else {
@@ -1745,7 +1749,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
                        rtlhal->oem_id = RT_CID_TOSHIBA;
                        break;
                case EEPROM_CID_QMI:
-                       rtlhal->oem_id = RT_CID_819x_QMI;
+                       rtlhal->oem_id = RT_CID_819X_QMI;
                        break;
                case EEPROM_CID_WHQL:
                default:
@@ -1764,14 +1768,14 @@ static void _rtl92ce_hal_customized_behavior(struct ieee80211_hw *hw)
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
        switch (rtlhal->oem_id) {
-       case RT_CID_819x_HP:
+       case RT_CID_819X_HP:
                pcipriv->ledctl.led_opendrain = true;
                break;
-       case RT_CID_819x_Lenovo:
+       case RT_CID_819X_LENOVO:
        case RT_CID_DEFAULT:
        case RT_CID_TOSHIBA:
        case RT_CID_CCX:
-       case RT_CID_819x_Acer:
+       case RT_CID_819X_ACER:
        case RT_CID_WHQL:
        default:
                break;
index 73262ca3864b2c219a14e3c8085cbdcb32fc32c3..98b22303c84d1849da10221e80cfce7d87568c5a 100644 (file)
@@ -30,6 +30,7 @@
 #include "../wifi.h"
 #include "../pci.h"
 #include "../ps.h"
+#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "hw.h"
@@ -198,18 +199,7 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
        }
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_reg_arraylen; i = i + 2) {
-                       if (phy_regarray_table[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_regarray_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_regarray_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_regarray_table[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_regarray_table[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_regarray_table[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_regarray_table[i]);
                        rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
                                      phy_regarray_table[i + 1]);
                        udelay(1);
@@ -245,18 +235,7 @@ bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
 
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
-                       if (phy_regarray_table_pg[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_regarray_table_pg[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_regarray_table_pg[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_regarray_table_pg[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_regarray_table_pg[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_regarray_table_pg[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_regarray_table_pg[i]);
 
                        _rtl92c_store_pwrIndex_diffrate_offset(hw,
                                               phy_regarray_table_pg[i],
@@ -305,46 +284,16 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
        switch (rfpath) {
        case RF90_PATH_A:
                for (i = 0; i < radioa_arraylen; i = i + 2) {
-                       if (radioa_array_table[i] == 0xfe)
-                               mdelay(50);
-                       else if (radioa_array_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (radioa_array_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (radioa_array_table[i] == 0xfb)
-                               udelay(50);
-                       else if (radioa_array_table[i] == 0xfa)
-                               udelay(5);
-                       else if (radioa_array_table[i] == 0xf9)
-                               udelay(1);
-                       else {
-                               rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
-                                             RFREG_OFFSET_MASK,
-                                             radioa_array_table[i + 1]);
-                               udelay(1);
-                       }
+                       rtl_rfreg_delay(hw, rfpath, radioa_array_table[i],
+                                       RFREG_OFFSET_MASK,
+                                       radioa_array_table[i + 1]);
                }
                break;
        case RF90_PATH_B:
                for (i = 0; i < radiob_arraylen; i = i + 2) {
-                       if (radiob_array_table[i] == 0xfe) {
-                               mdelay(50);
-                       } else if (radiob_array_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (radiob_array_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (radiob_array_table[i] == 0xfb)
-                               udelay(50);
-                       else if (radiob_array_table[i] == 0xfa)
-                               udelay(5);
-                       else if (radiob_array_table[i] == 0xf9)
-                               udelay(1);
-                       else {
-                               rtl_set_rfreg(hw, rfpath, radiob_array_table[i],
-                                             RFREG_OFFSET_MASK,
-                                             radiob_array_table[i + 1]);
-                               udelay(1);
-                       }
+                       rtl_rfreg_delay(hw, rfpath, radiob_array_table[i],
+                                       RFREG_OFFSET_MASK,
+                                       radiob_array_table[i + 1]);
                }
                break;
        case RF90_PATH_C:
@@ -355,6 +304,8 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                         "switch case not processed\n");
                break;
+       default:
+               break;
        }
        return true;
 }
index 8922ecb47ad245cdb7d1b759f44c558f97e52173..ed703a1b3b7c1c54490efb803e804000a2d43342 100644 (file)
 #define        BWORD1                                  0xc
 #define        BWORD                                   0xf
 
-#define        MASKBYTE0                               0xff
-#define        MASKBYTE1                               0xff00
-#define        MASKBYTE2                               0xff0000
-#define        MASKBYTE3                               0xff000000
-#define        MASKHWORD                               0xffff0000
-#define        MASKLWORD                               0x0000ffff
-#define        MASKDWORD                               0xffffffff
-#define        MASK12BITS                              0xfff
-#define        MASKH4BITS                              0xf0000000
-#define MASKOFDM_D                             0xffc00000
-#define        MASKCCK                                 0x3f3f3f3f
-
-#define        MASK4BITS                               0x0f
-#define        MASK20BITS                              0xfffff
-#define RFREG_OFFSET_MASK                      0xfffff
-
 #define        BENABLE                                 0x1
 #define        BDISABLE                                0x0
 
index 114858d46158916600cdb6ad38e54723c8bd5618..8f04817cb7ec810bc70dea859895788fd9259687 100644 (file)
@@ -426,7 +426,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
 
 void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
                          struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-                         struct ieee80211_tx_info *info,
+                         u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                          struct ieee80211_sta *sta,
                          struct sk_buff *skb,
                          u8 hw_queue, struct rtl_tcb_desc *tcb_desc)
@@ -666,7 +666,8 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
                      "H2C Tx Cmd Content", pdesc, TX_DESC_SIZE);
 }
 
-void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl92ce_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                     u8 desc_name, u8 *val)
 {
        if (istx) {
                switch (desc_name) {
index a7cdd514cb2e2bfd6a86aa629a997a3d1c5f5db8..9a39ec4204dda77ef6e268be0396d3399ffc33f8 100644 (file)
@@ -711,8 +711,8 @@ struct rx_desc_92c {
 } __packed;
 
 void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
-                         struct ieee80211_hdr *hdr,
-                         u8 *pdesc, struct ieee80211_tx_info *info,
+                         struct ieee80211_hdr *hdr, u8 *pdesc,
+                         u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                          struct ieee80211_sta *sta,
                          struct sk_buff *skb, u8 hw_queue,
                          struct rtl_tcb_desc *ptcb_desc);
@@ -720,7 +720,8 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
                           struct rtl_stats *stats,
                           struct ieee80211_rx_status *rx_status,
                           u8 *pdesc, struct sk_buff *skb);
-void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl92ce_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                     u8 desc_name, u8 *val);
 u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name);
 void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
 void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
index 468bf73cc883f41bf26222cc7aa52e17c5ed96a3..68b5c7e92cfbc2c6a76580a2d1dbb3297730c64f 100644 (file)
@@ -394,7 +394,7 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw)
                        if (rtlefuse->eeprom_did == 0x8176) {
                                if ((rtlefuse->eeprom_svid == 0x103C &&
                                     rtlefuse->eeprom_smid == 0x1629))
-                                       rtlhal->oem_id = RT_CID_819x_HP;
+                                       rtlhal->oem_id = RT_CID_819X_HP;
                                else
                                        rtlhal->oem_id = RT_CID_DEFAULT;
                        } else {
@@ -405,7 +405,7 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw)
                        rtlhal->oem_id = RT_CID_TOSHIBA;
                        break;
                case EEPROM_CID_QMI:
-                       rtlhal->oem_id = RT_CID_819x_QMI;
+                       rtlhal->oem_id = RT_CID_819X_QMI;
                        break;
                case EEPROM_CID_WHQL:
                default:
@@ -423,14 +423,14 @@ static void _rtl92cu_hal_customized_behavior(struct ieee80211_hw *hw)
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
        switch (rtlhal->oem_id) {
-       case RT_CID_819x_HP:
+       case RT_CID_819X_HP:
                usb_priv->ledctl.led_opendrain = true;
                break;
-       case RT_CID_819x_Lenovo:
+       case RT_CID_819X_LENOVO:
        case RT_CID_DEFAULT:
        case RT_CID_TOSHIBA:
        case RT_CID_CCX:
-       case RT_CID_819x_Acer:
+       case RT_CID_819X_ACER:
        case RT_CID_WHQL:
        default:
                break;
@@ -985,6 +985,17 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        int err = 0;
        static bool iqk_initialized;
+       unsigned long flags;
+
+       /* As this function can take a very long time (up to 350 ms)
+        * and can be called with irqs disabled, reenable the irqs
+        * to let the other devices continue being serviced.
+        *
+        * It is safe doing so since our own interrupts will only be enabled
+        * in a subsequent step.
+        */
+       local_save_flags(flags);
+       local_irq_enable();
 
        rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU;
        err = _rtl92cu_init_mac(hw);
@@ -997,7 +1008,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         "Failed to download FW. Init HW without FW now..\n");
                err = 1;
-               return err;
+               goto exit;
        }
        rtlhal->last_hmeboxnum = 0; /* h2c */
        _rtl92cu_phy_param_tab_init(hw);
@@ -1034,6 +1045,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
        _InitPABias(hw);
        _update_mac_setting(hw);
        rtl92c_dm_init(hw);
+exit:
+       local_irq_restore(flags);
        return err;
 }
 
@@ -1379,11 +1392,13 @@ void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-       u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+       u32 reg_rcr;
 
        if (rtlpriv->psc.rfpwr_state != ERFON)
                return;
 
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
        if (check_bssid) {
                u8 tmp;
                if (IS_NORMAL_CHIP(rtlhal->version)) {
@@ -1795,7 +1810,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                                          e_aci);
                                break;
                        }
-                       if (rtlusb->acm_method != eAcmWay2_SW)
+                       if (rtlusb->acm_method != EACMWAY2_SW)
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                         HW_VAR_ACM_CTRL, &e_aci);
                        break;
index 0c09240eadccdee5fe6fd6ab266c561d7019684b..9831ff1128ca93385377a302187ee5c0d887b56d 100644 (file)
@@ -30,6 +30,7 @@
 #include "../wifi.h"
 #include "../pci.h"
 #include "../ps.h"
+#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -188,18 +189,7 @@ bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
        }
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_reg_arraylen; i = i + 2) {
-                       if (phy_regarray_table[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_regarray_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_regarray_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_regarray_table[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_regarray_table[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_regarray_table[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_regarray_table[i]);
                        rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
                                      phy_regarray_table[i + 1]);
                        udelay(1);
@@ -236,18 +226,7 @@ bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
        phy_regarray_table_pg = rtlphy->hwparam_tables[PHY_REG_PG].pdata;
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
-                       if (phy_regarray_table_pg[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_regarray_table_pg[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_regarray_table_pg[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_regarray_table_pg[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_regarray_table_pg[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_regarray_table_pg[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_regarray_table_pg[i]);
                        _rtl92c_store_pwrIndex_diffrate_offset(hw,
                                                  phy_regarray_table_pg[i],
                                                  phy_regarray_table_pg[i + 1],
@@ -294,46 +273,16 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
        switch (rfpath) {
        case RF90_PATH_A:
                for (i = 0; i < radioa_arraylen; i = i + 2) {
-                       if (radioa_array_table[i] == 0xfe)
-                               mdelay(50);
-                       else if (radioa_array_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (radioa_array_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (radioa_array_table[i] == 0xfb)
-                               udelay(50);
-                       else if (radioa_array_table[i] == 0xfa)
-                               udelay(5);
-                       else if (radioa_array_table[i] == 0xf9)
-                               udelay(1);
-                       else {
-                               rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
-                                             RFREG_OFFSET_MASK,
-                                             radioa_array_table[i + 1]);
-                               udelay(1);
-                       }
+                       rtl_rfreg_delay(hw, rfpath, radioa_array_table[i],
+                                       RFREG_OFFSET_MASK,
+                                       radioa_array_table[i + 1]);
                }
                break;
        case RF90_PATH_B:
                for (i = 0; i < radiob_arraylen; i = i + 2) {
-                       if (radiob_array_table[i] == 0xfe) {
-                               mdelay(50);
-                       } else if (radiob_array_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (radiob_array_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (radiob_array_table[i] == 0xfb)
-                               udelay(50);
-                       else if (radiob_array_table[i] == 0xfa)
-                               udelay(5);
-                       else if (radiob_array_table[i] == 0xf9)
-                               udelay(1);
-                       else {
-                               rtl_set_rfreg(hw, rfpath, radiob_array_table[i],
-                                             RFREG_OFFSET_MASK,
-                                             radiob_array_table[i + 1]);
-                               udelay(1);
-                       }
+                       rtl_rfreg_delay(hw, rfpath, radiob_array_table[i],
+                                       RFREG_OFFSET_MASK,
+                                       radiob_array_table[i + 1]);
                }
                break;
        case RF90_PATH_C:
@@ -344,6 +293,8 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                         "switch case not processed\n");
                break;
+       default:
+               break;
        }
        return true;
 }
index 1bc21ccfa71b85f671afebb8d2826e43be45f9e9..035e0dc3922caf99311cb42c3dadea8e255c587c 100644 (file)
@@ -495,7 +495,7 @@ static void _rtl_tx_desc_checksum(u8 *txdesc)
 
 void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
                          struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-                         struct ieee80211_tx_info *info,
+                         u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                          struct ieee80211_sta *sta,
                          struct sk_buff *skb,
                          u8 queue_index,
index 725c53accc5839bbd30af97e753ab6b8d040ee48..fd8051dcd98a0295c4838750c6e4a3aded6920cb 100644 (file)
@@ -420,7 +420,7 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *,
                                           struct sk_buff_head *);
 void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
                          struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-                         struct ieee80211_tx_info *info,
+                         u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                          struct ieee80211_sta *sta,
                          struct sk_buff *skb,
                          u8 queue_index,
index 7908e1c85819409091abd71ba5b57595947ff909..304c443b89b261b3a633f276962e35ef536998f7 100644 (file)
@@ -194,15 +194,15 @@ static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
        rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 1); /* hold page C counter */
        rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 1); /*hold page D counter */
 
-       ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, BMASKDWORD);
+       ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD);
        falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff);
        falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16);
-       ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, BMASKDWORD);
+       ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
        falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
-       ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, BMASKDWORD);
+       ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
        falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
        falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
-       ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, BMASKDWORD);
+       ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
        falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
        falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
                                      falsealm_cnt->cnt_rate_illegal +
@@ -214,9 +214,9 @@ static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
        if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) {
                /* hold cck counter */
                rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag);
-               ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, BMASKBYTE0);
+               ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0);
                falsealm_cnt->cnt_cck_fail = ret_value;
-               ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, BMASKBYTE3);
+               ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3);
                falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
                rtl92d_release_cckandrw_pagea_ctl(hw, &flag);
        } else {
@@ -331,11 +331,11 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
        if (de_digtable->pre_cck_pd_state != de_digtable->cur_cck_pd_state) {
                if (de_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) {
                        rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag);
-                       rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0x83);
+                       rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83);
                        rtl92d_release_cckandrw_pagea_ctl(hw, &flag);
                } else {
                        rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag);
-                       rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0xcd);
+                       rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
                        rtl92d_release_cckandrw_pagea_ctl(hw, &flag);
                }
                de_digtable->pre_cck_pd_state = de_digtable->cur_cck_pd_state;
@@ -722,7 +722,7 @@ static void rtl92d_dm_rxgain_tracking_thermalmeter(struct ieee80211_hw *hw)
        RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
                 "===> Rx Gain %x\n", u4tmp);
        for (i = RF90_PATH_A; i < rtlpriv->phy.num_total_rfpath; i++)
-               rtl_set_rfreg(hw, i, 0x3C, BRFREGOFFSETMASK,
+               rtl_set_rfreg(hw, i, 0x3C, RFREG_OFFSET_MASK,
                              (rtlpriv->phy.reg_rf3c[i] & (~(0xF000))) | u4tmp);
 }
 
@@ -737,7 +737,7 @@ static void rtl92d_bandtype_2_4G(struct ieee80211_hw *hw, long *temp_cckg,
        /* Query CCK default setting From 0xa24 */
        rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag);
        temp_cck = rtl_get_bbreg(hw, RCCK0_TXFILTER2,
-                                BMASKDWORD) & BMASKCCK;
+                                MASKDWORD) & MASKCCK;
        rtl92d_release_cckandrw_pagea_ctl(hw, &flag);
        for (i = 0; i < CCK_TABLE_LENGTH; i++) {
                if (rtlpriv->dm.cck_inch14) {
@@ -896,9 +896,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
                rf = 1;
        if (thermalvalue) {
                ele_d = rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
-                                     BMASKDWORD) & BMASKOFDM_D;
+                                     MASKDWORD) & MASKOFDM_D;
                for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {
-                       if (ele_d == (ofdmswing_table[i] & BMASKOFDM_D)) {
+                       if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
                                ofdm_index_old[0] = (u8) i;
 
                                RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
@@ -910,10 +910,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
                }
                if (is2t) {
                        ele_d = rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE,
-                                             BMASKDWORD) & BMASKOFDM_D;
+                                             MASKDWORD) & MASKOFDM_D;
                        for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {
                                if (ele_d ==
-                                   (ofdmswing_table[i] & BMASKOFDM_D)) {
+                                   (ofdmswing_table[i] & MASKOFDM_D)) {
                                        ofdm_index_old[1] = (u8) i;
                                        RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
                                                 DBG_LOUD,
@@ -1091,10 +1091,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
                                value32 = (ele_d << 22) | ((ele_c & 0x3F) <<
                                          16) | ele_a;
                                rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
-                                             BMASKDWORD, value32);
+                                             MASKDWORD, value32);
 
                                value32 = (ele_c & 0x000003C0) >> 6;
-                               rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS,
+                               rtl_set_bbreg(hw, ROFDM0_XCTxAFE, MASKH4BITS,
                                              value32);
 
                                value32 = ((val_x * ele_d) >> 7) & 0x01;
@@ -1103,10 +1103,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
 
                        } else {
                                rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
-                                             BMASKDWORD,
+                                             MASKDWORD,
                                              ofdmswing_table
                                              [(u8)ofdm_index[0]]);
-                               rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS,
+                               rtl_set_bbreg(hw, ROFDM0_XCTxAFE, MASKH4BITS,
                                              0x00);
                                rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
                                              BIT(24), 0x00);
@@ -1204,21 +1204,21 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
                                                  ele_a;
                                        rtl_set_bbreg(hw,
                                                      ROFDM0_XBTxIQIMBALANCE,
-                                                     BMASKDWORD, value32);
+                                                     MASKDWORD, value32);
                                        value32 = (ele_c & 0x000003C0) >> 6;
                                        rtl_set_bbreg(hw, ROFDM0_XDTxAFE,
-                                                     BMASKH4BITS, value32);
+                                                     MASKH4BITS, value32);
                                        value32 = ((val_x * ele_d) >> 7) & 0x01;
                                        rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
                                                      BIT(28), value32);
                                } else {
                                        rtl_set_bbreg(hw,
                                                      ROFDM0_XBTxIQIMBALANCE,
-                                                     BMASKDWORD,
+                                                     MASKDWORD,
                                                      ofdmswing_table
                                                      [(u8) ofdm_index[1]]);
                                        rtl_set_bbreg(hw, ROFDM0_XDTxAFE,
-                                                     BMASKH4BITS, 0x00);
+                                                     MASKH4BITS, 0x00);
                                        rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
                                                      BIT(28), 0x00);
                                }
@@ -1229,10 +1229,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
                        }
                        RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
                                 "TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n",
-                                rtl_get_bbreg(hw, 0xc80, BMASKDWORD),
-                                rtl_get_bbreg(hw, 0xc94, BMASKDWORD),
+                                rtl_get_bbreg(hw, 0xc80, MASKDWORD),
+                                rtl_get_bbreg(hw, 0xc94, MASKDWORD),
                                 rtl_get_rfreg(hw, RF90_PATH_A, 0x24,
-                                              BRFREGOFFSETMASK));
+                                              RFREG_OFFSET_MASK));
                }
                if ((delta_iqk > rtlefuse->delta_iqk) &&
                    (rtlefuse->delta_iqk != 0)) {
index c4a7db9135d6e3850dcd8490e5e9165807178b64..2b08671004a0aa88b4c6ea270ebc4e7c8368aee6 100644 (file)
@@ -318,7 +318,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
        case HW_VAR_AC_PARAM: {
                u8 e_aci = *val;
                rtl92d_dm_init_edca_turbo(hw);
-               if (rtlpci->acm_method != eAcmWay2_SW)
+               if (rtlpci->acm_method != EACMWAY2_SW)
                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
                                                      &e_aci);
                break;
@@ -985,9 +985,9 @@ int rtl92de_hw_init(struct ieee80211_hw *hw)
        /* set default value after initialize RF,  */
        rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0);
        rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
-                       RF_CHNLBW, BRFREGOFFSETMASK);
+                       RF_CHNLBW, RFREG_OFFSET_MASK);
        rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1,
-                       RF_CHNLBW, BRFREGOFFSETMASK);
+                       RF_CHNLBW, RFREG_OFFSET_MASK);
 
        /*---- Set CCK and OFDM Block "ON"----*/
        if (rtlhal->current_bandtype == BAND_ON_2_4G)
@@ -1035,7 +1035,7 @@ int rtl92de_hw_init(struct ieee80211_hw *hw)
 
                                tmp_rega = rtl_get_rfreg(hw,
                                                  (enum radio_path)RF90_PATH_A,
-                                                 0x2a, BMASKDWORD);
+                                                 0x2a, MASKDWORD);
 
                                if (((tmp_rega & BIT(11)) == BIT(11)))
                                        break;
@@ -1138,11 +1138,13 @@ static int _rtl92de_set_media_status(struct ieee80211_hw *hw,
 void rtl92de_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       u32 reg_rcr = rtlpci->receive_config;
+       u32 reg_rcr;
 
        if (rtlpriv->psc.rfpwr_state != ERFON)
                return;
+
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
        if (check_bssid) {
                reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
@@ -1332,13 +1334,13 @@ void rtl92de_card_disable(struct ieee80211_hw *hw)
        /* c. ========RF OFF sequence==========  */
        /* 0x88c[23:20] = 0xf. */
        rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf);
-       rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00);
+       rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
 
        /* APSD_CTRL 0x600[7:0] = 0x40 */
        rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
 
        /* Close antenna 0,0xc04,0xd04 */
-       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0);
+       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0);
        rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0);
 
        /*  SYS_FUNC_EN 0x02[7:0] = 0xE2   reset BB state machine */
index 13196cc4b1d380279e7ce3096b5861ba14087b81..3d1f0dd4e52d89825710544078895752895b2c76 100644 (file)
@@ -30,6 +30,7 @@
 #include "../wifi.h"
 #include "../pci.h"
 #include "../ps.h"
+#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -242,7 +243,7 @@ void rtl92d_phy_set_bb_reg(struct ieee80211_hw *hw,
        else if (rtlhal->during_mac0init_radiob)
                /* mac0 use phy1 write radio_b. */
                dbi_direct = BIT(3) | BIT(2);
-       if (bitmask != BMASKDWORD) {
+       if (bitmask != MASKDWORD) {
                if (rtlhal->during_mac1init_radioa ||
                    rtlhal->during_mac0init_radiob)
                        originalvalue = rtl92de_read_dword_dbi(hw,
@@ -275,20 +276,20 @@ static u32 _rtl92d_phy_rf_serial_read(struct ieee80211_hw *hw,
        u32 retvalue;
 
        newoffset = offset;
-       tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD);
+       tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
        if (rfpath == RF90_PATH_A)
                tmplong2 = tmplong;
        else
-               tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD);
+               tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
        tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
                (newoffset << 23) | BLSSIREADEDGE;
-       rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD,
+       rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
                tmplong & (~BLSSIREADEDGE));
        udelay(10);
-       rtl_set_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD, tmplong2);
+       rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
        udelay(50);
        udelay(50);
-       rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD,
+       rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
                tmplong | BLSSIREADEDGE);
        udelay(10);
        if (rfpath == RF90_PATH_A)
@@ -321,7 +322,7 @@ static void _rtl92d_phy_rf_serial_write(struct ieee80211_hw *hw,
        newoffset = offset;
        /* T65 RF */
        data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
-       rtl_set_bbreg(hw, pphyreg->rf3wire_offset, BMASKDWORD, data_and_addr);
+       rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n",
                 rfpath, pphyreg->rf3wire_offset, data_and_addr);
 }
@@ -362,7 +363,7 @@ void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
                return;
        spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
        if (rtlphy->rf_mode != RF_OP_BY_FW) {
-               if (bitmask != BRFREGOFFSETMASK) {
+               if (bitmask != RFREG_OFFSET_MASK) {
                        original_value = _rtl92d_phy_rf_serial_read(hw,
                                rfpath, regaddr);
                        bitshift = _rtl92d_phy_calculate_bit_shift(bitmask);
@@ -567,19 +568,8 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
                 " ===> phy:Rtl819XPHY_REG_Array_PG\n");
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_reg_arraylen; i = i + 2) {
-                       if (phy_regarray_table[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_regarray_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_regarray_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_regarray_table[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_regarray_table[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_regarray_table[i] == 0xf9)
-                               udelay(1);
-                       rtl_set_bbreg(hw, phy_regarray_table[i], BMASKDWORD,
+                       rtl_addr_delay(phy_regarray_table[i]);
+                       rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
                                      phy_regarray_table[i + 1]);
                        udelay(1);
                        RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
@@ -591,7 +581,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
                if (rtlhal->interfaceindex == 0) {
                        for (i = 0; i < agctab_arraylen; i = i + 2) {
                                rtl_set_bbreg(hw, agctab_array_table[i],
-                                       BMASKDWORD,
+                                       MASKDWORD,
                                        agctab_array_table[i + 1]);
                                /* Add 1us delay between BB/RF register
                                 * setting. */
@@ -607,7 +597,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
                        if (rtlhal->current_bandtype == BAND_ON_2_4G) {
                                for (i = 0; i < agctab_arraylen; i = i + 2) {
                                        rtl_set_bbreg(hw, agctab_array_table[i],
-                                               BMASKDWORD,
+                                               MASKDWORD,
                                                agctab_array_table[i + 1]);
                                        /* Add 1us delay between BB/RF register
                                         * setting. */
@@ -623,7 +613,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
                                for (i = 0; i < agctab_5garraylen; i = i + 2) {
                                        rtl_set_bbreg(hw,
                                                agctab_5garray_table[i],
-                                               BMASKDWORD,
+                                               MASKDWORD,
                                                agctab_5garray_table[i + 1]);
                                        /* Add 1us delay between BB/RF registeri
                                         * setting. */
@@ -705,18 +695,7 @@ static bool _rtl92d_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
        phy_regarray_table_pg = rtl8192de_phy_reg_array_pg;
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
-                       if (phy_regarray_table_pg[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_regarray_table_pg[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_regarray_table_pg[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_regarray_table_pg[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_regarray_table_pg[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_regarray_table_pg[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_regarray_table_pg[i]);
                        _rtl92d_store_pwrindex_diffrate_offset(hw,
                                phy_regarray_table_pg[i],
                                phy_regarray_table_pg[i + 1],
@@ -843,54 +822,16 @@ bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
        switch (rfpath) {
        case RF90_PATH_A:
                for (i = 0; i < radioa_arraylen; i = i + 2) {
-                       if (radioa_array_table[i] == 0xfe) {
-                               mdelay(50);
-                       } else if (radioa_array_table[i] == 0xfd) {
-                               /* delay_ms(5); */
-                               mdelay(5);
-                       } else if (radioa_array_table[i] == 0xfc) {
-                               /* delay_ms(1); */
-                               mdelay(1);
-                       } else if (radioa_array_table[i] == 0xfb) {
-                               udelay(50);
-                       } else if (radioa_array_table[i] == 0xfa) {
-                               udelay(5);
-                       } else if (radioa_array_table[i] == 0xf9) {
-                               udelay(1);
-                       } else {
-                               rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
-                                             BRFREGOFFSETMASK,
-                                             radioa_array_table[i + 1]);
-                               /*  Add 1us delay between BB/RF register set. */
-                               udelay(1);
-                       }
+                       rtl_rfreg_delay(hw, rfpath, radioa_array_table[i],
+                                       RFREG_OFFSET_MASK,
+                                       radioa_array_table[i + 1]);
                }
                break;
        case RF90_PATH_B:
                for (i = 0; i < radiob_arraylen; i = i + 2) {
-                       if (radiob_array_table[i] == 0xfe) {
-                               /* Delay specific ms. Only RF configuration
-                                * requires delay. */
-                               mdelay(50);
-                       } else if (radiob_array_table[i] == 0xfd) {
-                               /* delay_ms(5); */
-                               mdelay(5);
-                       } else if (radiob_array_table[i] == 0xfc) {
-                               /* delay_ms(1); */
-                               mdelay(1);
-                       } else if (radiob_array_table[i] == 0xfb) {
-                               udelay(50);
-                       } else if (radiob_array_table[i] == 0xfa) {
-                               udelay(5);
-                       } else if (radiob_array_table[i] == 0xf9) {
-                               udelay(1);
-                       } else {
-                               rtl_set_rfreg(hw, rfpath, radiob_array_table[i],
-                                             BRFREGOFFSETMASK,
-                                             radiob_array_table[i + 1]);
-                               /*  Add 1us delay between BB/RF register set. */
-                               udelay(1);
-                       }
+                       rtl_rfreg_delay(hw, rfpath, radiob_array_table[i],
+                                       RFREG_OFFSET_MASK,
+                                       radiob_array_table[i + 1]);
                }
                break;
        case RF90_PATH_C:
@@ -911,13 +852,13 @@ void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
 
        rtlphy->default_initialgain[0] =
-           (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, BMASKBYTE0);
+           (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
        rtlphy->default_initialgain[1] =
-           (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, BMASKBYTE0);
+           (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
        rtlphy->default_initialgain[2] =
-           (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, BMASKBYTE0);
+           (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
        rtlphy->default_initialgain[3] =
-           (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, BMASKBYTE0);
+           (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
        RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
                 "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n",
                 rtlphy->default_initialgain[0],
@@ -925,9 +866,9 @@ void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
                 rtlphy->default_initialgain[2],
                 rtlphy->default_initialgain[3]);
        rtlphy->framesync = (u8)rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
-                                             BMASKBYTE0);
+                                             MASKBYTE0);
        rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
-                                             BMASKDWORD);
+                                             MASKDWORD);
        RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
                 "Default framesync (0x%x) = 0x%x\n",
                 ROFDM0_RXDETECTOR3, rtlphy->framesync);
@@ -1106,7 +1047,7 @@ static void _rtl92d_phy_stop_trx_before_changeband(struct ieee80211_hw *hw)
 {
        rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0);
        rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0);
-       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x00);
+       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x00);
        rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x0);
 }
 
@@ -1168,7 +1109,7 @@ static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        u32 imr_num = MAX_RF_IMR_INDEX;
-       u32 rfmask = BRFREGOFFSETMASK;
+       u32 rfmask = RFREG_OFFSET_MASK;
        u8 group, i;
        unsigned long flag = 0;
 
@@ -1211,7 +1152,7 @@ static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw,
                        for (i = 0; i < imr_num; i++) {
                                rtl_set_rfreg(hw, (enum radio_path)rfpath,
                                              rf_reg_for_5g_swchnl_normal[i],
-                                             BRFREGOFFSETMASK,
+                                             RFREG_OFFSET_MASK,
                                              rf_imr_param_normal[0][0][i]);
                        }
                        rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4,
@@ -1329,7 +1270,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
                        if (i == 0 && (rtlhal->macphymode == DUALMAC_DUALPHY)) {
                                rtl_set_rfreg(hw, (enum radio_path)path,
                                              rf_reg_for_c_cut_5g[i],
-                                             BRFREGOFFSETMASK, 0xE439D);
+                                             RFREG_OFFSET_MASK, 0xE439D);
                        } else if (rf_reg_for_c_cut_5g[i] == RF_SYN_G4) {
                                u4tmp2 = (rf_reg_pram_c_5g[index][i] &
                                     0x7FF) | (u4tmp << 11);
@@ -1337,11 +1278,11 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
                                        u4tmp2 &= ~(BIT(7) | BIT(6));
                                rtl_set_rfreg(hw, (enum radio_path)path,
                                              rf_reg_for_c_cut_5g[i],
-                                             BRFREGOFFSETMASK, u4tmp2);
+                                             RFREG_OFFSET_MASK, u4tmp2);
                        } else {
                                rtl_set_rfreg(hw, (enum radio_path)path,
                                              rf_reg_for_c_cut_5g[i],
-                                             BRFREGOFFSETMASK,
+                                             RFREG_OFFSET_MASK,
                                              rf_reg_pram_c_5g[index][i]);
                        }
                        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
@@ -1351,7 +1292,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
                                 path, index,
                                 rtl_get_rfreg(hw, (enum radio_path)path,
                                               rf_reg_for_c_cut_5g[i],
-                                              BRFREGOFFSETMASK));
+                                              RFREG_OFFSET_MASK));
                }
                if (need_pwr_down)
                        _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue);
@@ -1381,7 +1322,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
                                     i++) {
                                        rtl_set_rfreg(hw, rfpath,
                                                rf_for_c_cut_5g_internal_pa[i],
-                                               BRFREGOFFSETMASK,
+                                               RFREG_OFFSET_MASK,
                                                rf_pram_c_5g_int_pa[index][i]);
                                        RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
                                                 "offset 0x%x value 0x%x path %d index %d\n",
@@ -1422,13 +1363,13 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
                        if (rf_reg_for_c_cut_2g[i] == RF_SYN_G7)
                                rtl_set_rfreg(hw, (enum radio_path)path,
                                        rf_reg_for_c_cut_2g[i],
-                                       BRFREGOFFSETMASK,
+                                       RFREG_OFFSET_MASK,
                                        (rf_reg_param_for_c_cut_2g[index][i] |
                                        BIT(17)));
                        else
                                rtl_set_rfreg(hw, (enum radio_path)path,
                                              rf_reg_for_c_cut_2g[i],
-                                             BRFREGOFFSETMASK,
+                                             RFREG_OFFSET_MASK,
                                              rf_reg_param_for_c_cut_2g
                                              [index][i]);
                        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
@@ -1438,14 +1379,14 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel)
                                 rf_reg_mask_for_c_cut_2g[i], path, index,
                                 rtl_get_rfreg(hw, (enum radio_path)path,
                                               rf_reg_for_c_cut_2g[i],
-                                              BRFREGOFFSETMASK));
+                                              RFREG_OFFSET_MASK));
                }
                RTPRINT(rtlpriv, FINIT, INIT_IQK,
                        "cosa ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n",
                        rf_syn_g4_for_c_cut_2g | (u4tmp << 11));
 
                rtl_set_rfreg(hw, (enum radio_path)path, RF_SYN_G4,
-                             BRFREGOFFSETMASK,
+                             RFREG_OFFSET_MASK,
                              rf_syn_g4_for_c_cut_2g | (u4tmp << 11));
                if (need_pwr_down)
                        _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue);
@@ -1493,41 +1434,41 @@ static u8 _rtl92d_phy_patha_iqk(struct ieee80211_hw *hw, bool configpathb)
        /* path-A IQK setting */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Path-A IQK setting!\n");
        if (rtlhal->interfaceindex == 0) {
-               rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c1f);
-               rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c1f);
+               rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1f);
+               rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c1f);
        } else {
-               rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c22);
-               rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c22);
+               rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c22);
+               rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c22);
        }
-       rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140102);
-       rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x28160206);
+       rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140102);
+       rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160206);
        /* path-B IQK setting */
        if (configpathb) {
-               rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x10008c22);
-               rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x10008c22);
-               rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140102);
-               rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x28160206);
+               rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x10008c22);
+               rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x10008c22);
+               rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140102);
+               rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x28160206);
        }
        /* LO calibration setting */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "LO calibration setting!\n");
-       rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911);
+       rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
        /* One shot, path A LOK & IQK */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "One shot, path A LOK & IQK!\n");
-       rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000);
-       rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000);
+       rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+       rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
        /* delay x ms */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                "Delay %d ms for One shot, path A LOK & IQK\n",
                IQK_DELAY_TIME);
        mdelay(IQK_DELAY_TIME);
        /* Check failed */
-       regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
+       regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xeac = 0x%x\n", regeac);
-       rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD);
+       rege94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xe94 = 0x%x\n", rege94);
-       rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD);
+       rege9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xe9c = 0x%x\n", rege9c);
-       regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD);
+       regea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xea4 = 0x%x\n", regea4);
        if (!(regeac & BIT(28)) && (((rege94 & 0x03FF0000) >> 16) != 0x142) &&
            (((rege9c & 0x03FF0000) >> 16) != 0x42))
@@ -1563,42 +1504,42 @@ static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw,
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Path A IQK!\n");
        /* path-A IQK setting */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Path-A IQK setting!\n");
-       rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f);
-       rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f);
-       rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140307);
-       rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68160960);
+       rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x18008c1f);
+       rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x18008c1f);
+       rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140307);
+       rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x68160960);
        /* path-B IQK setting */
        if (configpathb) {
-               rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f);
-               rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f);
-               rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82110000);
-               rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68110000);
+               rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x18008c2f);
+               rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x18008c2f);
+               rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82110000);
+               rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x68110000);
        }
        /* LO calibration setting */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "LO calibration setting!\n");
-       rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911);
+       rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
        /* path-A PA on */
-       rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x07000f60);
-       rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, 0x66e60e30);
+       rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, 0x07000f60);
+       rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, MASKDWORD, 0x66e60e30);
        for (i = 0; i < retrycount; i++) {
                /* One shot, path A LOK & IQK */
                RTPRINT(rtlpriv, FINIT, INIT_IQK,
                        "One shot, path A LOK & IQK!\n");
-               rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000);
-               rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000);
+               rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+               rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
                /* delay x ms */
                RTPRINT(rtlpriv, FINIT, INIT_IQK,
                        "Delay %d ms for One shot, path A LOK & IQK.\n",
                        IQK_DELAY_TIME);
                mdelay(IQK_DELAY_TIME * 10);
                /* Check failed */
-               regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
+               regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xeac = 0x%x\n", regeac);
-               rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD);
+               rege94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xe94 = 0x%x\n", rege94);
-               rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD);
+               rege9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xe9c = 0x%x\n", rege9c);
-               regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD);
+               regea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xea4 = 0x%x\n", regea4);
                if (!(regeac & TxOKBit) &&
                     (((rege94 & 0x03FF0000) >> 16) != 0x142)) {
@@ -1620,9 +1561,9 @@ static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw,
                }
        }
        /* path A PA off */
-       rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD,
+       rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD,
                      rtlphy->iqk_bb_backup[0]);
-       rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD,
+       rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, MASKDWORD,
                      rtlphy->iqk_bb_backup[1]);
        return result;
 }
@@ -1637,22 +1578,22 @@ static u8 _rtl92d_phy_pathb_iqk(struct ieee80211_hw *hw)
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Path B IQK!\n");
        /* One shot, path B LOK & IQK */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "One shot, path A LOK & IQK!\n");
-       rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000002);
-       rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000000);
+       rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002);
+       rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000);
        /* delay x ms  */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                "Delay %d ms for One shot, path B LOK & IQK\n", IQK_DELAY_TIME);
        mdelay(IQK_DELAY_TIME);
        /* Check failed */
-       regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
+       regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xeac = 0x%x\n", regeac);
-       regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD);
+       regeb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xeb4 = 0x%x\n", regeb4);
-       regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD);
+       regebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xebc = 0x%x\n", regebc);
-       regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD);
+       regec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xec4 = 0x%x\n", regec4);
-       regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD);
+       regecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xecc = 0x%x\n", regecc);
        if (!(regeac & BIT(31)) && (((regeb4 & 0x03FF0000) >> 16) != 0x142) &&
            (((regebc & 0x03FF0000) >> 16) != 0x42))
@@ -1680,31 +1621,31 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw)
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Path B IQK!\n");
        /* path-A IQK setting */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Path-A IQK setting!\n");
-       rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f);
-       rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f);
-       rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82110000);
-       rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68110000);
+       rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x18008c1f);
+       rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x18008c1f);
+       rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82110000);
+       rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x68110000);
 
        /* path-B IQK setting */
-       rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f);
-       rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f);
-       rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140307);
-       rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68160960);
+       rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x18008c2f);
+       rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x18008c2f);
+       rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140307);
+       rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x68160960);
 
        /* LO calibration setting */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "LO calibration setting!\n");
-       rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911);
+       rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
 
        /* path-B PA on */
-       rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x0f600700);
-       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, 0x061f0d30);
+       rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, 0x0f600700);
+       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, MASKDWORD, 0x061f0d30);
 
        for (i = 0; i < retrycount; i++) {
                /* One shot, path B LOK & IQK */
                RTPRINT(rtlpriv, FINIT, INIT_IQK,
                        "One shot, path A LOK & IQK!\n");
-               rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xfa000000);
-               rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000);
+               rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xfa000000);
+               rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
 
                /* delay x ms */
                RTPRINT(rtlpriv, FINIT, INIT_IQK,
@@ -1712,15 +1653,15 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw)
                mdelay(IQK_DELAY_TIME * 10);
 
                /* Check failed */
-               regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
+               regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xeac = 0x%x\n", regeac);
-               regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD);
+               regeb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xeb4 = 0x%x\n", regeb4);
-               regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD);
+               regebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xebc = 0x%x\n", regebc);
-               regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD);
+               regec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xec4 = 0x%x\n", regec4);
-               regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD);
+               regecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "0xecc = 0x%x\n", regecc);
                if (!(regeac & BIT(31)) &&
                    (((regeb4 & 0x03FF0000) >> 16) != 0x142))
@@ -1738,9 +1679,9 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw)
        }
 
        /* path B PA off */
-       rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD,
+       rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD,
                      rtlphy->iqk_bb_backup[0]);
-       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD,
+       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, MASKDWORD,
                      rtlphy->iqk_bb_backup[2]);
        return result;
 }
@@ -1754,7 +1695,7 @@ static void _rtl92d_phy_save_adda_registers(struct ieee80211_hw *hw,
 
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Save ADDA parameters.\n");
        for (i = 0; i < regnum; i++)
-               adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], BMASKDWORD);
+               adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], MASKDWORD);
 }
 
 static void _rtl92d_phy_save_mac_registers(struct ieee80211_hw *hw,
@@ -1779,7 +1720,7 @@ static void _rtl92d_phy_reload_adda_registers(struct ieee80211_hw *hw,
        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                "Reload ADDA power saving parameters !\n");
        for (i = 0; i < regnum; i++)
-               rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, adda_backup[i]);
+               rtl_set_bbreg(hw, adda_reg[i], MASKDWORD, adda_backup[i]);
 }
 
 static void _rtl92d_phy_reload_mac_registers(struct ieee80211_hw *hw,
@@ -1807,7 +1748,7 @@ static void _rtl92d_phy_path_adda_on(struct ieee80211_hw *hw,
                pathon = rtlpriv->rtlhal.interfaceindex == 0 ?
                    0x04db25a4 : 0x0b1b25a4;
        for (i = 0; i < IQK_ADDA_REG_NUM; i++)
-               rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, pathon);
+               rtl_set_bbreg(hw, adda_reg[i], MASKDWORD, pathon);
 }
 
 static void _rtl92d_phy_mac_setting_calibration(struct ieee80211_hw *hw,
@@ -1830,9 +1771,9 @@ static void _rtl92d_phy_patha_standby(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Path-A standby mode!\n");
 
-       rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x0);
-       rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, 0x00010000);
-       rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
+       rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, MASKDWORD, 0x00010000);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
 }
 
 static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode)
@@ -1843,8 +1784,8 @@ static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode)
        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                "BB Switch to %s mode!\n", pi_mode ? "PI" : "SI");
        mode = pi_mode ? 0x01000100 : 0x01000000;
-       rtl_set_bbreg(hw, 0x820, BMASKDWORD, mode);
-       rtl_set_bbreg(hw, 0x828, BMASKDWORD, mode);
+       rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
+       rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
 }
 
 static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
@@ -1875,7 +1816,7 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
 
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "IQK for 2.4G :Start!!!\n");
        if (t == 0) {
-               bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD);
+               bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "==>0x%08x\n", bbvalue);
                RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n",
                        is2t ? "2T2R" : "1T1R");
@@ -1898,40 +1839,40 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
                _rtl92d_phy_pimode_switch(hw, true);
 
        rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00);
-       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600);
-       rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4);
-       rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22204000);
+       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600);
+       rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4);
+       rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22204000);
        rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f);
        if (is2t) {
-               rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD,
+               rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, MASKDWORD,
                              0x00010000);
-               rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, BMASKDWORD,
+               rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, MASKDWORD,
                              0x00010000);
        }
        /* MAC settings */
        _rtl92d_phy_mac_setting_calibration(hw, iqk_mac_reg,
                                            rtlphy->iqk_mac_backup);
        /* Page B init */
-       rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000);
+       rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000);
        if (is2t)
-               rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000);
+               rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000);
        /* IQ calibration setting */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "IQK setting!\n");
-       rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000);
-       rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x01007c00);
-       rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+       rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
+       rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800);
        for (i = 0; i < retrycount; i++) {
                patha_ok = _rtl92d_phy_patha_iqk(hw, is2t);
                if (patha_ok == 0x03) {
                        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                                "Path A IQK Success!!\n");
-                       result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) &
+                       result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
                                        0x3FF0000) >> 16;
-                       result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) &
+                       result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
                                        0x3FF0000) >> 16;
-                       result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) &
+                       result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) &
                                        0x3FF0000) >> 16;
-                       result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) &
+                       result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) &
                                        0x3FF0000) >> 16;
                        break;
                } else if (i == (retrycount - 1) && patha_ok == 0x01) {
@@ -1939,9 +1880,9 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
                        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                                "Path A IQK Only  Tx Success!!\n");
 
-                       result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) &
+                       result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
                                        0x3FF0000) >> 16;
-                       result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) &
+                       result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
                                        0x3FF0000) >> 16;
                }
        }
@@ -1957,22 +1898,22 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
                                RTPRINT(rtlpriv, FINIT, INIT_IQK,
                                        "Path B IQK Success!!\n");
                                result[t][4] = (rtl_get_bbreg(hw, 0xeb4,
-                                              BMASKDWORD) & 0x3FF0000) >> 16;
+                                              MASKDWORD) & 0x3FF0000) >> 16;
                                result[t][5] = (rtl_get_bbreg(hw, 0xebc,
-                                              BMASKDWORD) & 0x3FF0000) >> 16;
+                                              MASKDWORD) & 0x3FF0000) >> 16;
                                result[t][6] = (rtl_get_bbreg(hw, 0xec4,
-                                              BMASKDWORD) & 0x3FF0000) >> 16;
+                                              MASKDWORD) & 0x3FF0000) >> 16;
                                result[t][7] = (rtl_get_bbreg(hw, 0xecc,
-                                              BMASKDWORD) & 0x3FF0000) >> 16;
+                                              MASKDWORD) & 0x3FF0000) >> 16;
                                break;
                        } else if (i == (retrycount - 1) && pathb_ok == 0x01) {
                                /* Tx IQK OK */
                                RTPRINT(rtlpriv, FINIT, INIT_IQK,
                                        "Path B Only Tx IQK Success!!\n");
                                result[t][4] = (rtl_get_bbreg(hw, 0xeb4,
-                                              BMASKDWORD) & 0x3FF0000) >> 16;
+                                              MASKDWORD) & 0x3FF0000) >> 16;
                                result[t][5] = (rtl_get_bbreg(hw, 0xebc,
-                                              BMASKDWORD) & 0x3FF0000) >> 16;
+                                              MASKDWORD) & 0x3FF0000) >> 16;
                        }
                }
                if (0x00 == pathb_ok)
@@ -1984,7 +1925,7 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                "IQK:Back to BB mode, load original value!\n");
 
-       rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
        if (t != 0) {
                /* Switch back BB to SI mode after finish IQ Calibration. */
                if (!rtlphy->rfpi_enable)
@@ -2004,8 +1945,8 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8],
                                                          rtlphy->iqk_bb_backup,
                                                          IQK_BB_REG_NUM - 1);
                /* load 0xe30 IQC default value */
-               rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x01008c00);
-               rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x01008c00);
+               rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00);
+               rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00);
        }
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "<==\n");
 }
@@ -2042,7 +1983,7 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw,
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "IQK for 5G NORMAL:Start!!!\n");
        mdelay(IQK_DELAY_TIME * 20);
        if (t == 0) {
-               bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD);
+               bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, MASKDWORD);
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "==>0x%08x\n", bbvalue);
                RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n",
                        is2t ? "2T2R" : "1T1R");
@@ -2072,38 +2013,38 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw,
        if (!rtlphy->rfpi_enable)
                _rtl92d_phy_pimode_switch(hw, true);
        rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00);
-       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600);
-       rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4);
-       rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22208000);
+       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600);
+       rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4);
+       rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22208000);
        rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f);
 
        /* Page B init */
-       rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000);
+       rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000);
        if (is2t)
-               rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000);
+               rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000);
        /* IQ calibration setting  */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "IQK setting!\n");
-       rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000);
-       rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x10007c00);
-       rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+       rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x10007c00);
+       rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800);
        patha_ok = _rtl92d_phy_patha_iqk_5g_normal(hw, is2t);
        if (patha_ok == 0x03) {
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Path A IQK Success!!\n");
-               result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) &
+               result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
                                0x3FF0000) >> 16;
-               result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) &
+               result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
                                0x3FF0000) >> 16;
-               result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) &
+               result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) &
                                0x3FF0000) >> 16;
-               result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) &
+               result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) &
                                0x3FF0000) >> 16;
        } else if (patha_ok == 0x01) {  /* Tx IQK OK */
                RTPRINT(rtlpriv, FINIT, INIT_IQK,
                        "Path A IQK Only  Tx Success!!\n");
 
-               result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) &
+               result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
                                0x3FF0000) >> 16;
-               result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) &
+               result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
                                0x3FF0000) >> 16;
        } else {
                RTPRINT(rtlpriv, FINIT, INIT_IQK,  "Path A IQK Fail!!\n");
@@ -2116,20 +2057,20 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw,
                if (pathb_ok == 0x03) {
                        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                                "Path B IQK Success!!\n");
-                       result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) &
+                       result[t][4] = (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) &
                             0x3FF0000) >> 16;
-                       result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) &
+                       result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
                             0x3FF0000) >> 16;
-                       result[t][6] = (rtl_get_bbreg(hw, 0xec4, BMASKDWORD) &
+                       result[t][6] = (rtl_get_bbreg(hw, 0xec4, MASKDWORD) &
                             0x3FF0000) >> 16;
-                       result[t][7] = (rtl_get_bbreg(hw, 0xecc, BMASKDWORD) &
+                       result[t][7] = (rtl_get_bbreg(hw, 0xecc, MASKDWORD) &
                             0x3FF0000) >> 16;
                } else if (pathb_ok == 0x01) { /* Tx IQK OK */
                        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                                "Path B Only Tx IQK Success!!\n");
-                       result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) &
+                       result[t][4] = (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) &
                             0x3FF0000) >> 16;
-                       result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) &
+                       result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
                             0x3FF0000) >> 16;
                } else {
                        RTPRINT(rtlpriv, FINIT, INIT_IQK,
@@ -2140,7 +2081,7 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw,
        /* Back to BB mode, load original value */
        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                "IQK:Back to BB mode, load original value!\n");
-       rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
        if (t != 0) {
                if (is2t)
                        _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg,
@@ -2240,7 +2181,7 @@ static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw,
                return;
        } else if (iqk_ok) {
                oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
-                       BMASKDWORD) >> 22) & 0x3FF;     /* OFDM0_D */
+                       MASKDWORD) >> 22) & 0x3FF;      /* OFDM0_D */
                val_x = result[final_candidate][0];
                if ((val_x & 0x00000200) != 0)
                        val_x = val_x | 0xFFFFFC00;
@@ -2271,7 +2212,7 @@ static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw,
                                      ((val_y * oldval_0 >> 7) & 0x1));
                RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xC80 = 0x%x\n",
                        rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE,
-                                     BMASKDWORD));
+                                     MASKDWORD));
                if (txonly) {
                        RTPRINT(rtlpriv, FINIT, INIT_IQK,  "only Tx OK\n");
                        return;
@@ -2299,7 +2240,7 @@ static void _rtl92d_phy_pathb_fill_iqk_matrix(struct ieee80211_hw *hw,
                return;
        } else if (iqk_ok) {
                oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE,
-                                         BMASKDWORD) >> 22) & 0x3FF;
+                                         MASKDWORD) >> 22) & 0x3FF;
                val_x = result[final_candidate][4];
                if ((val_x & 0x00000200) != 0)
                        val_x = val_x | 0xFFFFFC00;
@@ -2657,7 +2598,7 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t)
                rf_mode[index] = rtl_read_byte(rtlpriv, offset);
                /* 2. Set RF mode = standby mode */
                rtl_set_rfreg(hw, (enum radio_path)index, RF_AC,
-                             BRFREGOFFSETMASK, 0x010000);
+                             RFREG_OFFSET_MASK, 0x010000);
                if (rtlpci->init_ready) {
                        /* switch CV-curve control by LC-calibration */
                        rtl_set_rfreg(hw, (enum radio_path)index, RF_SYN_G7,
@@ -2667,16 +2608,16 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t)
                                      0x08000, 0x01);
                }
                u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, RF_SYN_G6,
-                                 BRFREGOFFSETMASK);
+                                 RFREG_OFFSET_MASK);
                while ((!(u4tmp & BIT(11))) && timecount <= timeout) {
                        mdelay(50);
                        timecount += 50;
                        u4tmp = rtl_get_rfreg(hw, (enum radio_path)index,
-                                             RF_SYN_G6, BRFREGOFFSETMASK);
+                                             RF_SYN_G6, RFREG_OFFSET_MASK);
                }
                RTPRINT(rtlpriv, FINIT, INIT_IQK,
                        "PHY_LCK finish delay for %d ms=2\n", timecount);
-               u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, BRFREGOFFSETMASK);
+               u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, RFREG_OFFSET_MASK);
                if (index == 0 && rtlhal->interfaceindex == 0) {
                        RTPRINT(rtlpriv, FINIT, INIT_IQK,
                                "path-A / 5G LCK\n");
@@ -2696,9 +2637,9 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t)
                                      0x7f, i);
 
                        rtl_set_rfreg(hw, (enum radio_path)index, 0x4D,
-                               BRFREGOFFSETMASK, 0x0);
+                               RFREG_OFFSET_MASK, 0x0);
                        readval = rtl_get_rfreg(hw, (enum radio_path)index,
-                                         0x4F, BRFREGOFFSETMASK);
+                                         0x4F, RFREG_OFFSET_MASK);
                        curvecount_val[2 * i + 1] = (readval & 0xfffe0) >> 5;
                        /* reg 0x4f [4:0] */
                        /* reg 0x50 [19:10] */
@@ -2912,7 +2853,7 @@ static bool _rtl92d_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
                                }
                                rtl_set_rfreg(hw, (enum radio_path)rfpath,
                                              currentcmd->para1,
-                                             BRFREGOFFSETMASK,
+                                             RFREG_OFFSET_MASK,
                                              rtlphy->rfreg_chnlval[rfpath]);
                                _rtl92d_phy_reload_imr_setting(hw, channel,
                                                               rfpath);
@@ -2960,7 +2901,7 @@ u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw)
        if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY &&
            rtlhal->bandset == BAND_ON_BOTH) {
                ret_value = rtl_get_bbreg(hw, RFPGA0_XAB_RFPARAMETER,
-                                         BMASKDWORD);
+                                         MASKDWORD);
                if (rtlphy->current_channel > 14 && !(ret_value & BIT(0)))
                        rtl92d_phy_switch_wirelessband(hw, BAND_ON_5G);
                else if (rtlphy->current_channel <= 14 && (ret_value & BIT(0)))
@@ -3112,7 +3053,7 @@ static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw)
        /* a.   TXPAUSE 0x522[7:0] = 0xFF  Pause MAC TX queue  */
        rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
        /* b.   RF path 0 offset 0x00 = 0x00  disable RF  */
-       rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00);
+       rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
        /* c.   APSD_CTRL 0x600[7:0] = 0x40 */
        rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
        /* d. APSD_CTRL 0x600[7:0] = 0x00
@@ -3120,12 +3061,12 @@ static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw)
         * RF path 0 offset 0x00 = 0x00
         * APSD_CTRL 0x600[7:0] = 0x40
         * */
-       u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK);
+       u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
        while (u4btmp != 0 && delay > 0) {
                rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0);
-               rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00);
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
                rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
-               u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK);
+               u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
                delay--;
        }
        if (delay == 0) {
@@ -3468,9 +3409,9 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
                /* 5G LAN ON */
                rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0xa);
                /* TX BB gain shift*1,Just for testchip,0xc80,0xc88 */
-               rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD,
+               rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD,
                              0x40000100);
-               rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD,
+               rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD,
                              0x40000100);
                if (rtlhal->macphymode == DUALMAC_DUALPHY) {
                        rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW,
@@ -3524,16 +3465,16 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
                rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0x0);
                /* TX BB gain shift,Just for testchip,0xc80,0xc88 */
                if (rtlefuse->internal_pa_5g[0])
-                       rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD,
+                       rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD,
                                      0x2d4000b5);
                else
-                       rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD,
+                       rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD,
                                      0x20000080);
                if (rtlefuse->internal_pa_5g[1])
-                       rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD,
+                       rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD,
                                      0x2d4000b5);
                else
-                       rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD,
+                       rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD,
                                      0x20000080);
                if (rtlhal->macphymode == DUALMAC_DUALPHY) {
                        rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW,
@@ -3560,8 +3501,8 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
                }
        }
        /* update IQK related settings */
-       rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, BMASKDWORD, 0x40000100);
-       rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, BMASKDWORD, 0x40000100);
+       rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, MASKDWORD, 0x40000100);
+       rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, MASKDWORD, 0x40000100);
        rtl_set_bbreg(hw, ROFDM0_XCTxAFE, 0xF0000000, 0x00);
        rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(30) | BIT(28) |
                      BIT(26) | BIT(24), 0x00);
@@ -3590,7 +3531,7 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
        /* DMDP */
        if (rtlphy->rf_type == RF_1T1R) {
                /* Use antenna 0,0xc04,0xd04 */
-               rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x11);
+               rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x11);
                rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x1);
 
                /* enable ad/da clock1 for dual-phy reg0x888 */
@@ -3612,7 +3553,7 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
        } else {
                /* Single PHY */
                /* Use antenna 0 & 1,0xc04,0xd04 */
-               rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x33);
+               rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x33);
                rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x3);
                /* disable ad/da clock1,0x888 */
                rtl_set_bbreg(hw, RFPGA0_ADDALLOCKEN, BIT(12) | BIT(13), 0);
@@ -3620,9 +3561,9 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)
        for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
             rfpath++) {
                rtlphy->rfreg_chnlval[rfpath] = rtl_get_rfreg(hw, rfpath,
-                                               RF_CHNLBW, BRFREGOFFSETMASK);
+                                               RF_CHNLBW, RFREG_OFFSET_MASK);
                rtlphy->reg_rf3c[rfpath] = rtl_get_rfreg(hw, rfpath, 0x3C,
-                       BRFREGOFFSETMASK);
+                       RFREG_OFFSET_MASK);
        }
        for (i = 0; i < 2; i++)
                RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "RF 0x18 = 0x%x\n",
index b7498c5bafc56f25e887831e9e2f9640e811794c..7f29b8d765b37cf22e1a8cf362144d4229a2f583 100644 (file)
 #define        BWORD1                                  0xc
 #define        BDWORD                                  0xf
 
-#define        BMASKBYTE0                              0xff
-#define        BMASKBYTE1                              0xff00
-#define        BMASKBYTE2                              0xff0000
-#define        BMASKBYTE3                              0xff000000
-#define        BMASKHWORD                              0xffff0000
-#define        BMASKLWORD                              0x0000ffff
-#define        BMASKDWORD                              0xffffffff
-#define        BMASK12BITS                             0xfff
-#define        BMASKH4BITS                             0xf0000000
-#define BMASKOFDM_D                            0xffc00000
-#define        BMASKCCK                                0x3f3f3f3f
-
-#define BRFREGOFFSETMASK                       0xfffff
-
 #endif
index 20144e0b4142d9f53e9f892a49c415c013160cd0..6a6ac540d5b505edf81bb34ee93e9effdd664230 100644 (file)
@@ -125,7 +125,7 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
        }
 
        tmpval = tx_agc[RF90_PATH_A] & 0xff;
-       rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, BMASKBYTE1, tmpval);
+       rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
        RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
                "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n",
                tmpval, RTXAGC_A_CCK1_MCS32);
@@ -135,7 +135,7 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
                "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n",
                tmpval, RTXAGC_B_CCK11_A_CCK2_11);
        tmpval = tx_agc[RF90_PATH_B] >> 24;
-       rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, BMASKBYTE0, tmpval);
+       rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
        RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
                "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n",
                tmpval, RTXAGC_B_CCK11_A_CCK2_11);
@@ -360,7 +360,7 @@ static void _rtl92d_write_ofdm_power_reg(struct ieee80211_hw *hw,
                        regoffset = regoffset_a[index];
                else
                        regoffset = regoffset_b[index];
-               rtl_set_bbreg(hw, regoffset, BMASKDWORD, writeval);
+               rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
                RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
                        "Set 0x%x = %08x\n", regoffset, writeval);
                if (((get_rf_type(rtlphy) == RF_2T2R) &&
index 0eb0f4ae592054f7ebf1ee9182169fc57adbc11c..99c2ab5dfcebfe230a70da60c42a8427509dd9b9 100644 (file)
@@ -545,7 +545,7 @@ static void _rtl92de_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
 
 void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
                          struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-                         struct ieee80211_tx_info *info,
+                         u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                          struct ieee80211_sta *sta,
                          struct sk_buff *skb,
                          u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
@@ -786,7 +786,8 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw,
        SET_TX_DESC_OWN(pdesc, 1);
 }
 
-void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                     u8 desc_name, u8 *val)
 {
        if (istx) {
                switch (desc_name) {
index c1b5dfb79d53ce2d2ebf843db65c14999d92196c..fb5cf0634e8d882ef9f308f631a3272fca69b5c3 100644 (file)
@@ -728,8 +728,8 @@ struct rx_desc_92d {
 } __packed;
 
 void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
-                         struct ieee80211_hdr *hdr,
-                         u8 *pdesc, struct ieee80211_tx_info *info,
+                         struct ieee80211_hdr *hdr, u8 *pdesc,
+                         u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                          struct ieee80211_sta *sta,
                          struct sk_buff *skb, u8 hw_queue,
                          struct rtl_tcb_desc *ptcb_desc);
@@ -737,7 +737,8 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw,
                           struct rtl_stats *stats,
                           struct ieee80211_rx_status *rx_status,
                           u8 *pdesc, struct sk_buff *skb);
-void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                     u8 desc_name, u8 *val);
 u32 rtl92de_get_desc(u8 *pdesc, bool istx, u8 desc_name);
 void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
 void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
index 4f461786a7eb24abb3ae49a1dbccc4311d54ea58..3015af167b2ba5d14214887a671147776cc9b3a8 100644 (file)
@@ -251,7 +251,7 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                        u8 e_aci = *val;
                        rtl92s_dm_init_edca_turbo(hw);
 
-                       if (rtlpci->acm_method != eAcmWay2_SW)
+                       if (rtlpci->acm_method != EACMWAY2_SW)
                                rtlpriv->cfg->ops->set_hw_reg(hw,
                                                 HW_VAR_ACM_CTRL,
                                                 &e_aci);
@@ -955,7 +955,7 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
        u8 tmp_byte = 0;
-
+       unsigned long flags;
        bool rtstatus = true;
        u8 tmp_u1b;
        int err = false;
@@ -967,6 +967,16 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
 
        rtlpci->being_init_adapter = true;
 
+       /* As this function can take a very long time (up to 350 ms)
+        * and can be called with irqs disabled, reenable the irqs
+        * to let the other devices continue being serviced.
+        *
+        * It is safe doing so since our own interrupts will only be enabled
+        * in a subsequent step.
+        */
+       local_save_flags(flags);
+       local_irq_enable();
+
        rtlpriv->intf_ops->disable_aspm(hw);
 
        /* 1. MAC Initialize */
@@ -984,7 +994,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         "Failed to download FW. Init HW without FW now... "
                         "Please copy FW into /lib/firmware/rtlwifi\n");
-               return 1;
+               err = 1;
+               goto exit;
        }
 
        /* After FW download, we have to reset MAC register */
@@ -997,7 +1008,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
        /* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */
        if (!rtl92s_phy_mac_config(hw)) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "MAC Config failed\n");
-               return rtstatus;
+               err = rtstatus;
+               goto exit;
        }
 
        /* because last function modify RCR, so we update
@@ -1016,7 +1028,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
        /* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */
        if (!rtl92s_phy_bb_config(hw)) {
                RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "BB Config failed\n");
-               return rtstatus;
+               err = rtstatus;
+               goto exit;
        }
 
        /* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */
@@ -1033,7 +1046,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
 
        if (!rtl92s_phy_rf_config(hw)) {
                RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "RF Config failed\n");
-               return rtstatus;
+               err = rtstatus;
+               goto exit;
        }
 
        /* After read predefined TXT, we must set BB/MAC/RF
@@ -1122,8 +1136,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
 
        rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON);
        rtl92s_dm_init(hw);
+exit:
+       local_irq_restore(flags);
        rtlpci->being_init_adapter = false;
-
        return err;
 }
 
@@ -1135,12 +1150,13 @@ void rtl92se_set_mac_addr(struct rtl_io *io, const u8 *addr)
 void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       u32 reg_rcr = rtlpci->receive_config;
+       u32 reg_rcr;
 
        if (rtlpriv->psc.rfpwr_state != ERFON)
                return;
 
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
        if (check_bssid) {
                reg_rcr |= (RCR_CBSSID);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
index 9c092e6eb3fe85d5707e7c652dc647ac8c486dcb..77c5b5f352441a3a2a2d0c26b5627266aa15d5d9 100644 (file)
@@ -30,6 +30,7 @@
 #include "../wifi.h"
 #include "../pci.h"
 #include "../ps.h"
+#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -833,18 +834,7 @@ static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype)
 
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_reg_len; i = i + 2) {
-                       if (phy_reg_table[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_reg_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_reg_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_reg_table[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_reg_table[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_reg_table[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_reg_table[i]);
 
                        /* Add delay for ECS T20 & LG malow platform, */
                        udelay(1);
@@ -886,18 +876,7 @@ static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw,
 
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) {
-                       if (phy_regarray2xtxr_table[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_regarray2xtxr_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_regarray2xtxr_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_regarray2xtxr_table[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_regarray2xtxr_table[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_regarray2xtxr_table[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_regarray2xtxr_table[i]);
 
                        rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i],
                                phy_regarray2xtxr_table[i + 1],
@@ -920,18 +899,7 @@ static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw,
 
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_pg_len; i = i + 3) {
-                       if (phy_table_pg[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_table_pg[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_table_pg[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_table_pg[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_table_pg[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_table_pg[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_table_pg[i]);
 
                        _rtl92s_store_pwrindex_diffrate_offset(hw,
                                        phy_table_pg[i],
@@ -1034,28 +1002,9 @@ u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath)
        switch (rfpath) {
        case RF90_PATH_A:
                for (i = 0; i < radio_a_tblen; i = i + 2) {
-                       if (radio_a_table[i] == 0xfe)
-                               /* Delay specific ms. Only RF configuration
-                                * requires delay. */
-                               mdelay(50);
-                       else if (radio_a_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (radio_a_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (radio_a_table[i] == 0xfb)
-                               udelay(50);
-                       else if (radio_a_table[i] == 0xfa)
-                               udelay(5);
-                       else if (radio_a_table[i] == 0xf9)
-                               udelay(1);
-                       else
-                               rtl92s_phy_set_rf_reg(hw, rfpath,
-                                                     radio_a_table[i],
-                                                     MASK20BITS,
-                                                     radio_a_table[i + 1]);
+                       rtl_rfreg_delay(hw, rfpath, radio_a_table[i],
+                                       MASK20BITS, radio_a_table[i + 1]);
 
-                       /* Add delay for ECS T20 & LG malow platform */
-                       udelay(1);
                }
 
                /* PA Bias current for inferiority IC */
@@ -1063,28 +1012,8 @@ u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath)
                break;
        case RF90_PATH_B:
                for (i = 0; i < radio_b_tblen; i = i + 2) {
-                       if (radio_b_table[i] == 0xfe)
-                               /* Delay specific ms. Only RF configuration
-                                * requires delay.*/
-                               mdelay(50);
-                       else if (radio_b_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (radio_b_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (radio_b_table[i] == 0xfb)
-                               udelay(50);
-                       else if (radio_b_table[i] == 0xfa)
-                               udelay(5);
-                       else if (radio_b_table[i] == 0xf9)
-                               udelay(1);
-                       else
-                               rtl92s_phy_set_rf_reg(hw, rfpath,
-                                                     radio_b_table[i],
-                                                     MASK20BITS,
-                                                     radio_b_table[i + 1]);
-
-                       /* Add delay for ECS T20 & LG malow platform */
-                       udelay(1);
+                       rtl_rfreg_delay(hw, rfpath, radio_b_table[i],
+                                       MASK20BITS, radio_b_table[i + 1]);
                }
                break;
        case RF90_PATH_C:
index c81c8359194007893412cd3d55f1da054b1bc645..e13043479b71a91fa8343f8124d3a29e4e08252c 100644 (file)
 
 #define        BTX_AGCRATECCK                          0x7f00
 
-#define        MASKBYTE0                               0xff
-#define        MASKBYTE1                               0xff00
-#define        MASKBYTE2                               0xff0000
-#define        MASKBYTE3                               0xff000000
-#define        MASKHWORD                               0xffff0000
-#define        MASKLWORD                               0x0000ffff
-#define        MASKDWORD                               0xffffffff
-
-#define        MAKS12BITS                              0xfffff
-#define        MASK20BITS                              0xfffff
-#define RFREG_OFFSET_MASK                      0xfffff
-
 #endif
index 92d38ab3c60e87861f992411e3774aeceed30f56..78a81c1e390bdd4052c64fd9cc4fe0a54b406aa8 100644 (file)
@@ -52,7 +52,7 @@ static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel,
        /* We only care about the path A for legacy. */
        if (rtlefuse->eeprom_version < 2) {
                pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf);
-       } else if (rtlefuse->eeprom_version >= 2) {
+       } else {
                legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff
                                                [RF90_PATH_A][chnl - 1];
 
index 163a681962c621e6c817b19b54e0fbdc74ba22fd..36b48be8329c08dad5474f43600f2b11d8fcf279 100644 (file)
@@ -336,7 +336,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
 
 void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
                struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-               struct ieee80211_tx_info *info,
+               u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                struct ieee80211_sta *sta,
                struct sk_buff *skb,
                u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
@@ -573,7 +573,8 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
        }
 }
 
-void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                     u8 desc_name, u8 *val)
 {
        if (istx) {
                switch (desc_name) {
index 64dd66f287c182a25949126d303925124a24bd71..5a13f17e3b41c7603e92646f7205af989607c59c 100644 (file)
@@ -29,8 +29,9 @@
 #ifndef __REALTEK_PCI92SE_TRX_H__
 #define __REALTEK_PCI92SE_TRX_H__
 
-void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
-                         u8 *pdesc, struct ieee80211_tx_info *info,
+void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
+                         struct ieee80211_hdr *hdr, u8 *pdesc,
+                         u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                          struct ieee80211_sta *sta,
                          struct sk_buff *skb, u8 hw_queue,
                          struct rtl_tcb_desc *ptcb_desc);
@@ -39,7 +40,8 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg,
 bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
                           struct ieee80211_rx_status *rx_status, u8 *pdesc,
                           struct sk_buff *skb);
-void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                     u8 desc_name, u8 *val);
 u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name);
 void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
 
index 4ed731f09b1ff3f0d57a99e25b80b2dd0fe516b1..9c34a85fdb89f1acf280e20722d81ccb2b1b0511 100644 (file)
@@ -10,7 +10,6 @@ rtl8723ae-objs :=             \
                led.o           \
                phy.o           \
                pwrseq.o        \
-               pwrseqcmd.o     \
                rf.o            \
                sw.o            \
                table.o         \
index 8c110356dff9824bcfc729530aa260a7643a4521..debe261a7eeb9026f2940db194ff25f1b1d0fe8b 100644 (file)
 #define E_CUT_VERSION                  BIT(14)
 #define        RF_RL_ID                        (BIT(31)|BIT(30)|BIT(29)|BIT(28))
 
-enum version_8723e {
-       VERSION_TEST_UMC_CHIP_8723 = 0x0081,
-       VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089,
-       VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089,
-};
 
 /* MASK */
 #define IC_TYPE_MASK                   (BIT(0)|BIT(1)|BIT(2))
index a36eee28f9e7f7fe092b3f443a205e67292ef52c..863ddb3e2888b8e11d90a2aceefd5279ac0586e5 100644 (file)
@@ -35,6 +35,7 @@
 #include "def.h"
 #include "phy.h"
 #include "dm.h"
+#include "../rtl8723com/dm_common.h"
 #include "fw.h"
 #include "hal_btc.h"
 
@@ -483,16 +484,6 @@ static void rtl8723ae_dm_dig(struct ieee80211_hw *hw)
        rtl8723ae_dm_ctrl_initgain_by_twoport(hw);
 }
 
-static void rtl8723ae_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-
-       rtlpriv->dm.dynamic_txpower_enable = false;
-
-       rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
-       rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
-}
-
 static void rtl8723ae_dm_dynamic_txpower(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -585,19 +576,6 @@ void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw)
        }
 }
 
-static void rtl8723ae_dm_pwdmonitor(struct ieee80211_hw *hw)
-{
-}
-
-void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-
-       rtlpriv->dm.current_turbo_edca = false;
-       rtlpriv->dm.is_any_nonbepkts = false;
-       rtlpriv->dm.is_cur_rdlstate = false;
-}
-
 static void rtl8723ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -778,17 +756,6 @@ static void rtl8723ae_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
        }
 }
 
-static void rtl8723ae_dm_init_dynamic_bpowersaving(struct ieee80211_hw *hw)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-
-       rtlpriv->dm_pstable.pre_ccastate = CCA_MAX;
-       rtlpriv->dm_pstable.cur_ccasate = CCA_MAX;
-       rtlpriv->dm_pstable.pre_rfstate = RF_MAX;
-       rtlpriv->dm_pstable.cur_rfstate = RF_MAX;
-       rtlpriv->dm_pstable.rssi_val_min = 0;
-}
-
 void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 force_in_normal)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -905,11 +872,11 @@ void rtl8723ae_dm_init(struct ieee80211_hw *hw)
 
        rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
        rtl8723ae_dm_diginit(hw);
-       rtl8723ae_dm_init_dynamic_txpower(hw);
-       rtl8723ae_dm_init_edca_turbo(hw);
+       rtl8723_dm_init_dynamic_txpower(hw);
+       rtl8723_dm_init_edca_turbo(hw);
        rtl8723ae_dm_init_rate_adaptive_mask(hw);
        rtl8723ae_dm_initialize_txpower_tracking(hw);
-       rtl8723ae_dm_init_dynamic_bpowersaving(hw);
+       rtl8723_dm_init_dynamic_bb_powersaving(hw);
 }
 
 void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
@@ -930,7 +897,6 @@ void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
        if ((ppsc->rfpwr_state == ERFON) &&
            ((!fw_current_inpsmode) && fw_ps_awake) &&
            (!ppsc->rfchange_inprogress)) {
-               rtl8723ae_dm_pwdmonitor(hw);
                rtl8723ae_dm_dig(hw);
                rtl8723ae_dm_false_alarm_counter_statistics(hw);
                rtl8723ae_dm_dynamic_bpowersaving(hw);
index a372b0204456bbfee8f27205338697cd9dc8cba6..d253bb53d03e2ccde5b4f646e4fff6a154158836 100644 (file)
@@ -147,7 +147,6 @@ enum dm_dig_connect_e {
 void rtl8723ae_dm_init(struct ieee80211_hw *hw);
 void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw);
 void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw);
-void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw);
 void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
 void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
 void rtl8723ae_dm_bt_coexist(struct ieee80211_hw *hw);
index ba1502b172a6a05f3fb34aa0e97c7ef6a7260ac1..728b7563ad36a32eb5b989a3ddcf5738088dfbf6 100644 (file)
 #include "reg.h"
 #include "def.h"
 #include "fw.h"
-
-static void _rtl8723ae_enable_fw_download(struct ieee80211_hw *hw, bool enable)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u8 tmp;
-       if (enable) {
-               tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
-               rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
-
-               tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
-               rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
-
-               tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
-               rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
-       } else {
-               tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
-               rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
-
-               rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
-       }
-}
-
-static void _rtl8723ae_fw_block_write(struct ieee80211_hw *hw,
-                                     const u8 *buffer, u32 size)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u32 blockSize = sizeof(u32);
-       u8 *bufferPtr = (u8 *) buffer;
-       u32 *pu4BytePtr = (u32 *) buffer;
-       u32 i, offset, blockCount, remainSize;
-
-       blockCount = size / blockSize;
-       remainSize = size % blockSize;
-
-       for (i = 0; i < blockCount; i++) {
-               offset = i * blockSize;
-               rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
-                               *(pu4BytePtr + i));
-       }
-
-       if (remainSize) {
-               offset = blockCount * blockSize;
-               bufferPtr += offset;
-               for (i = 0; i < remainSize; i++) {
-                       rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
-                                                offset + i), *(bufferPtr + i));
-               }
-       }
-}
-
-static void _rtl8723ae_fw_page_write(struct ieee80211_hw *hw,
-                                    u32 page, const u8 *buffer, u32 size)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u8 value8;
-       u8 u8page = (u8) (page & 0x07);
-
-       value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
-
-       rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
-       _rtl8723ae_fw_block_write(hw, buffer, size);
-}
-
-static void _rtl8723ae_write_fw(struct ieee80211_hw *hw,
-                               enum version_8723e version, u8 *buffer,
-                               u32 size)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u8 *bufferPtr = (u8 *) buffer;
-       u32 page_nums, remain_size;
-       u32 page, offset;
-
-       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
-
-       page_nums = size / FW_8192C_PAGE_SIZE;
-       remain_size = size % FW_8192C_PAGE_SIZE;
-
-       if (page_nums > 6) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "Page numbers should not be greater then 6\n");
-       }
-
-       for (page = 0; page < page_nums; page++) {
-               offset = page * FW_8192C_PAGE_SIZE;
-               _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
-                                        FW_8192C_PAGE_SIZE);
-       }
-
-       if (remain_size) {
-               offset = page_nums * FW_8192C_PAGE_SIZE;
-               page = page_nums;
-               _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
-                                        remain_size);
-       }
-
-       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
-}
-
-static int _rtl8723ae_fw_free_to_go(struct ieee80211_hw *hw)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       int err = -EIO;
-       u32 counter = 0;
-       u32 value32;
-
-       do {
-               value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
-       } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
-                (!(value32 & FWDL_ChkSum_rpt)));
-
-       if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
-                        value32);
-               goto exit;
-       }
-
-       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-                "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
-
-       value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
-       value32 |= MCUFWDL_RDY;
-       value32 &= ~WINTINI_RDY;
-       rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
-
-       counter = 0;
-
-       do {
-               value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
-               if (value32 & WINTINI_RDY) {
-                       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-                                "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
-                                value32);
-                       err = 0;
-                       goto exit;
-               }
-
-               mdelay(FW_8192C_POLLING_DELAY);
-
-       } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
-
-       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
-
-exit:
-       return err;
-}
-
-int rtl8723ae_download_fw(struct ieee80211_hw *hw)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-       struct rtl8723ae_firmware_header *pfwheader;
-       u8 *pfwdata;
-       u32 fwsize;
-       int err;
-       enum version_8723e version = rtlhal->version;
-
-       if (!rtlhal->pfirmware)
-               return 1;
-
-       pfwheader = (struct rtl8723ae_firmware_header *)rtlhal->pfirmware;
-       pfwdata = (u8 *) rtlhal->pfirmware;
-       fwsize = rtlhal->fwsize;
-
-       if (IS_FW_HEADER_EXIST(pfwheader)) {
-               RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
-                        "Firmware Version(%d), Signature(%#x),Size(%d)\n",
-                        pfwheader->version, pfwheader->signature,
-                        (int)sizeof(struct rtl8723ae_firmware_header));
-
-               pfwdata = pfwdata + sizeof(struct rtl8723ae_firmware_header);
-               fwsize = fwsize - sizeof(struct rtl8723ae_firmware_header);
-       }
-
-       if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
-               rtl8723ae_firmware_selfreset(hw);
-               rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
-       }
-       _rtl8723ae_enable_fw_download(hw, true);
-       _rtl8723ae_write_fw(hw, version, pfwdata, fwsize);
-       _rtl8723ae_enable_fw_download(hw, false);
-
-       err = _rtl8723ae_fw_free_to_go(hw);
-       if (err) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "Firmware is not ready to run!\n");
-       } else {
-               RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-                        "Firmware is ready to run!\n");
-       }
-       return 0;
-}
+#include "../rtl8723com/fw_common.h"
 
 static bool rtl8723ae_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
 {
@@ -463,50 +271,6 @@ void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw,
        return;
 }
 
-void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
-{
-       u8 u1tmp;
-       u8 delay = 100;
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-
-       rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
-       u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
-
-       while (u1tmp & BIT(2)) {
-               delay--;
-               if (delay == 0)
-                       break;
-               udelay(50);
-               u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
-       }
-       if (delay == 0) {
-               u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
-               rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2)));
-       }
-}
-
-void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u8 u1_h2c_set_pwrmode[3] = { 0 };
-       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-
-       RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
-
-       SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
-       SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
-                                        (rtlpriv->mac80211.p2p) ?
-                                        ppsc->smart_ps : 1);
-       SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
-                                             ppsc->reg_max_lps_awakeintvl);
-
-       RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
-                     "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
-                     u1_h2c_set_pwrmode, 3);
-       rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
-
-}
-
 static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw,
                                       struct sk_buff *skb)
 {
@@ -812,7 +576,6 @@ void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
                        rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
 
                        p2p_ps_offload->offload_en = 1;
-
                        if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
                                p2p_ps_offload->role = 1;
                                p2p_ps_offload->allstasleep = 0;
@@ -836,3 +599,24 @@ void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
        }
        rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
 }
+
+void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 u1_h2c_set_pwrmode[3] = { 0 };
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
+
+       SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
+       SET_H2CCMD_PWRMODE_PARM_SMART_PS_23A(u1_h2c_set_pwrmode,
+                                            (rtlpriv->mac80211.p2p) ?
+                                            ppsc->smart_ps : 1);
+       SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
+                                             ppsc->reg_max_lps_awakeintvl);
+
+       RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+                     "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
+                     u1_h2c_set_pwrmode, 3);
+       rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
+}
index ed3b795e6980781a738f5883cb63401e28458970..d355b85dd9fe72aee073ec44c42908339b904e80 100644 (file)
@@ -34,7 +34,7 @@
 #define FW_8192C_END_ADDRESS                   0x3FFF
 #define FW_8192C_PAGE_SIZE                     4096
 #define FW_8192C_POLLING_DELAY                 5
-#define FW_8192C_POLLING_TIMEOUT_COUNT         1000
+#define FW_8192C_POLLING_TIMEOUT_COUNT         6000
 
 #define BEACON_PG                              0
 #define PSPOLL_PG                              2
@@ -65,21 +65,9 @@ struct rtl8723ae_firmware_header {
        u32 rsvd5;
 };
 
-enum rtl8192c_h2c_cmd {
-       H2C_AP_OFFLOAD = 0,
-       H2C_SETPWRMODE = 1,
-       H2C_JOINBSSRPT = 2,
-       H2C_RSVDPAGE = 3,
-       H2C_RSSI_REPORT = 4,
-       H2C_P2P_PS_CTW_CMD = 5,
-       H2C_P2P_PS_OFFLOAD = 6,
-       H2C_RA_MASK = 7,
-       MAX_H2CCMD
-};
-
 #define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)                 \
        SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
-#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val)             \
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS_23A(__ph2ccmd, __val)         \
        SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
 #define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val)        \
        SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
@@ -92,10 +80,8 @@ enum rtl8192c_h2c_cmd {
 #define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)            \
        SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
 
-int rtl8723ae_download_fw(struct ieee80211_hw *hw);
 void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
                            u32 cmd_len, u8 *p_cmdbuffer);
-void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw);
 void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
 void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
 void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
index 3d092e4b0b7fe5fbf909d59eb3b3e3e41481000c..48fee1be78c2f54e1e839cf1cec8e05be65b9094 100644 (file)
@@ -31,6 +31,8 @@
 #include "../pci.h"
 #include "dm.h"
 #include "fw.h"
+#include "../rtl8723com/fw_common.h"
+#include "../rtl8723com/fw_common.h"
 #include "phy.h"
 #include "reg.h"
 #include "hal_btc.h"
index 68c28340f791623f9e78b98d2568a48b3668a86a..5d534df8d90ca2529db7bd3413d05dd76883c2c2 100644 (file)
@@ -30,7 +30,9 @@
 #include "hal_btc.h"
 #include "../pci.h"
 #include "phy.h"
+#include "../rtl8723com/phy_common.h"
 #include "fw.h"
+#include "../rtl8723com/fw_common.h"
 #include "reg.h"
 #include "def.h"
 
@@ -391,13 +393,13 @@ static void rtl8723ae_dm_bt_set_sw_full_time_dac_swing(struct ieee80211_hw *hw,
        if (sw_dac_swing_on) {
                RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
                         "[BTCoex], SwDacSwing = 0x%x\n", sw_dac_swing_lvl);
-               rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000,
-                                        sw_dac_swing_lvl);
+               rtl8723_phy_set_bb_reg(hw, 0x880, 0xff000000,
+                                      sw_dac_swing_lvl);
                rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
        } else {
                RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
                         "[BTCoex], SwDacSwing Off!\n");
-               rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000, 0xc0);
+               rtl8723_phy_set_bb_reg(hw, 0x880, 0xff000000, 0xc0);
        }
 }
 
index c333dfd116b868a8aff3dcf780e04611860d7951..f4c9852d1e1ed1343f4873948dc64037ad211d8b 100644 (file)
 #include "def.h"
 #include "phy.h"
 #include "dm.h"
+#include "../rtl8723com/dm_common.h"
 #include "fw.h"
+#include "../rtl8723com/fw_common.h"
 #include "led.h"
 #include "hw.h"
-#include "pwrseqcmd.h"
 #include "pwrseq.h"
 #include "btc.h"
 
@@ -304,9 +305,9 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
                break; }
        case HW_VAR_AC_PARAM:{
                u8 e_aci = *((u8 *) val);
-               rtl8723ae_dm_init_edca_turbo(hw);
+               rtl8723_dm_init_edca_turbo(hw);
 
-               if (rtlpci->acm_method != eAcmWay2_SW)
+               if (rtlpci->acm_method != EACMWAY2_SW)
                        rtlpriv->cfg->ops->set_hw_reg(hw,
                                                      HW_VAR_ACM_CTRL,
                                                      (u8 *) (&e_aci));
@@ -880,23 +881,33 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw)
        bool rtstatus = true;
        int err;
        u8 tmp_u1b;
+       unsigned long flags;
 
        rtlpriv->rtlhal.being_init_adapter = true;
+       /* As this function can take a very long time (up to 350 ms)
+        * and can be called with irqs disabled, reenable the irqs
+        * to let the other devices continue being serviced.
+        *
+        * It is safe doing so since our own interrupts will only be enabled
+        * in a subsequent step.
+        */
+       local_save_flags(flags);
+       local_irq_enable();
+
        rtlpriv->intf_ops->disable_aspm(hw);
        rtstatus = _rtl8712e_init_mac(hw);
        if (rtstatus != true) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
                err = 1;
-               return err;
+               goto exit;
        }
 
-       err = rtl8723ae_download_fw(hw);
+       err = rtl8723_download_fw(hw, false);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         "Failed to download FW. Init HW without FW now..\n");
                err = 1;
-               rtlhal->fw_ready = false;
-               return err;
+               goto exit;
        } else {
                rtlhal->fw_ready = true;
        }
@@ -971,6 +982,8 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw)
                RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
        }
        rtl8723ae_dm_init(hw);
+exit:
+       local_irq_restore(flags);
        rtlpriv->rtlhal.being_init_adapter = false;
        return err;
 }
@@ -1112,12 +1125,13 @@ static int _rtl8723ae_set_media_status(struct ieee80211_hw *hw,
 void rtl8723ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       u32 reg_rcr = rtlpci->receive_config;
+       u32 reg_rcr;
 
        if (rtlpriv->psc.rfpwr_state != ERFON)
                return;
 
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+
        if (check_bssid == true) {
                reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
@@ -1153,7 +1167,7 @@ void rtl8723ae_set_qos(struct ieee80211_hw *hw, int aci)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-       rtl8723ae_dm_init_edca_turbo(hw);
+       rtl8723_dm_init_edca_turbo(hw);
        switch (aci) {
        case AC1_BK:
                rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
@@ -1655,7 +1669,7 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
                                    CHK_SVID_SMID(0x10EC, 0x9185))
                                        rtlhal->oem_id = RT_CID_TOSHIBA;
                                else if (rtlefuse->eeprom_svid == 0x1025)
-                                       rtlhal->oem_id = RT_CID_819x_Acer;
+                                       rtlhal->oem_id = RT_CID_819X_ACER;
                                else if (CHK_SVID_SMID(0x10EC, 0x6191) ||
                                         CHK_SVID_SMID(0x10EC, 0x6192) ||
                                         CHK_SVID_SMID(0x10EC, 0x6193) ||
@@ -1665,7 +1679,7 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
                                         CHK_SVID_SMID(0x10EC, 0x8191) ||
                                         CHK_SVID_SMID(0x10EC, 0x8192) ||
                                         CHK_SVID_SMID(0x10EC, 0x8193))
-                                       rtlhal->oem_id = RT_CID_819x_SAMSUNG;
+                                       rtlhal->oem_id = RT_CID_819X_SAMSUNG;
                                else if (CHK_SVID_SMID(0x10EC, 0x8195) ||
                                         CHK_SVID_SMID(0x10EC, 0x9195) ||
                                         CHK_SVID_SMID(0x10EC, 0x7194) ||
@@ -1673,24 +1687,24 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
                                         CHK_SVID_SMID(0x10EC, 0x8201) ||
                                         CHK_SVID_SMID(0x10EC, 0x8202) ||
                                         CHK_SVID_SMID(0x10EC, 0x9200))
-                                       rtlhal->oem_id = RT_CID_819x_Lenovo;
+                                       rtlhal->oem_id = RT_CID_819X_LENOVO;
                                else if (CHK_SVID_SMID(0x10EC, 0x8197) ||
                                         CHK_SVID_SMID(0x10EC, 0x9196))
-                                       rtlhal->oem_id = RT_CID_819x_CLEVO;
+                                       rtlhal->oem_id = RT_CID_819X_CLEVO;
                                else if (CHK_SVID_SMID(0x1028, 0x8194) ||
                                         CHK_SVID_SMID(0x1028, 0x8198) ||
                                         CHK_SVID_SMID(0x1028, 0x9197) ||
                                         CHK_SVID_SMID(0x1028, 0x9198))
-                                       rtlhal->oem_id = RT_CID_819x_DELL;
+                                       rtlhal->oem_id = RT_CID_819X_DELL;
                                else if (CHK_SVID_SMID(0x103C, 0x1629))
-                                       rtlhal->oem_id = RT_CID_819x_HP;
+                                       rtlhal->oem_id = RT_CID_819X_HP;
                                else if (CHK_SVID_SMID(0x1A32, 0x2315))
-                                       rtlhal->oem_id = RT_CID_819x_QMI;
+                                       rtlhal->oem_id = RT_CID_819X_QMI;
                                else if (CHK_SVID_SMID(0x10EC, 0x8203))
-                                       rtlhal->oem_id = RT_CID_819x_PRONETS;
+                                       rtlhal->oem_id = RT_CID_819X_PRONETS;
                                else if (CHK_SVID_SMID(0x1043, 0x84B5))
                                        rtlhal->oem_id =
-                                                RT_CID_819x_Edimax_ASUS;
+                                                RT_CID_819X_EDIMAX_ASUS;
                                else
                                        rtlhal->oem_id = RT_CID_DEFAULT;
                        } else if (rtlefuse->eeprom_did == 0x8178) {
@@ -1712,12 +1726,12 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
                                    CHK_SVID_SMID(0x10EC, 0x9185))
                                        rtlhal->oem_id = RT_CID_TOSHIBA;
                                else if (rtlefuse->eeprom_svid == 0x1025)
-                                       rtlhal->oem_id = RT_CID_819x_Acer;
+                                       rtlhal->oem_id = RT_CID_819X_ACER;
                                else if (CHK_SVID_SMID(0x10EC, 0x8186))
-                                       rtlhal->oem_id = RT_CID_819x_PRONETS;
+                                       rtlhal->oem_id = RT_CID_819X_PRONETS;
                                else if (CHK_SVID_SMID(0x1043, 0x8486))
                                        rtlhal->oem_id =
-                                                    RT_CID_819x_Edimax_ASUS;
+                                                    RT_CID_819X_EDIMAX_ASUS;
                                else
                                        rtlhal->oem_id = RT_CID_DEFAULT;
                        } else {
@@ -1731,7 +1745,7 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
                        rtlhal->oem_id = RT_CID_CCX;
                        break;
                case EEPROM_CID_QMI:
-                       rtlhal->oem_id = RT_CID_819x_QMI;
+                       rtlhal->oem_id = RT_CID_819X_QMI;
                        break;
                case EEPROM_CID_WHQL:
                                break;
index 5d318a85eda4047100eeec7c5297412c15d615fd..3ea78afdec734f6e31c9c1f5a63e8238e91ca318 100644 (file)
 #include "../wifi.h"
 #include "../pci.h"
 #include "../ps.h"
+#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
 #include "rf.h"
 #include "dm.h"
 #include "table.h"
+#include "../rtl8723com/phy_common.h"
 
 /* static forward definitions */
 static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw,
@@ -43,72 +45,17 @@ static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw,
 static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw,
                                    enum radio_path rfpath,
                                    u32 offset, u32 data);
-static u32 _phy_rf_serial_read(struct ieee80211_hw *hw,
-                              enum radio_path rfpath, u32 offset);
-static void _phy_rf_serial_write(struct ieee80211_hw *hw,
-                                enum radio_path rfpath, u32 offset, u32 data);
-static u32 _phy_calculate_bit_shift(u32 bitmask);
 static bool _phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
 static bool _phy_cfg_mac_w_header(struct ieee80211_hw *hw);
 static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype);
 static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype);
-static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw);
-static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
-                                     u32 cmdtableidx, u32 cmdtablesz,
-                                     enum swchnlcmd_id cmdid,
-                                     u32 para1, u32 para2,
-                                     u32 msdelay);
 static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
                                      u8 *stage, u8 *step, u32 *delay);
 static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
                                enum wireless_mode wirelessmode,
                                long power_indbm);
-static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
-                                 enum wireless_mode wirelessmode, u8 txpwridx);
 static void rtl8723ae_phy_set_io(struct ieee80211_hw *hw);
 
-u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
-                              u32 bitmask)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u32 returnvalue, originalvalue, bitshift;
-
-       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-                "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
-       originalvalue = rtl_read_dword(rtlpriv, regaddr);
-       bitshift = _phy_calculate_bit_shift(bitmask);
-       returnvalue = (originalvalue & bitmask) >> bitshift;
-
-       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-                "BBR MASK=0x%x Addr[0x%x]=0x%x\n", bitmask, regaddr,
-                originalvalue);
-
-       return returnvalue;
-}
-
-void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw,
-                             u32 regaddr, u32 bitmask, u32 data)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u32 originalvalue, bitshift;
-
-       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-                "regaddr(%#x), bitmask(%#x), data(%#x)\n", regaddr,
-                bitmask, data);
-
-       if (bitmask != MASKDWORD) {
-               originalvalue = rtl_read_dword(rtlpriv, regaddr);
-               bitshift = _phy_calculate_bit_shift(bitmask);
-               data = ((originalvalue & (~bitmask)) | (data << bitshift));
-       }
-
-       rtl_write_dword(rtlpriv, regaddr, data);
-
-       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-                "regaddr(%#x), bitmask(%#x), data(%#x)\n",
-                regaddr, bitmask, data);
-}
-
 u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
                               enum radio_path rfpath, u32 regaddr, u32 bitmask)
 {
@@ -124,11 +71,11 @@ u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
        spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
 
        if (rtlphy->rf_mode != RF_OP_BY_FW)
-               original_value = _phy_rf_serial_read(hw, rfpath, regaddr);
+               original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr);
        else
                original_value = _phy_fw_rf_serial_read(hw, rfpath, regaddr);
 
-       bitshift = _phy_calculate_bit_shift(bitmask);
+       bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
        readback_value = (original_value & bitmask) >> bitshift;
 
        spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
@@ -157,19 +104,19 @@ void rtl8723ae_phy_set_rf_reg(struct ieee80211_hw *hw,
 
        if (rtlphy->rf_mode != RF_OP_BY_FW) {
                if (bitmask != RFREG_OFFSET_MASK) {
-                       original_value = _phy_rf_serial_read(hw, rfpath,
-                                                            regaddr);
-                       bitshift = _phy_calculate_bit_shift(bitmask);
+                       original_value = rtl8723_phy_rf_serial_read(hw, rfpath,
+                                                                   regaddr);
+                       bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
                        data = ((original_value & (~bitmask)) |
                               (data << bitshift));
                }
 
-               _phy_rf_serial_write(hw, rfpath, regaddr, data);
+               rtl8723_phy_rf_serial_write(hw, rfpath, regaddr, data);
        } else {
                if (bitmask != RFREG_OFFSET_MASK) {
                        original_value = _phy_fw_rf_serial_read(hw, rfpath,
                                                                regaddr);
-                       bitshift = _phy_calculate_bit_shift(bitmask);
+                       bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
                        data = ((original_value & (~bitmask)) |
                               (data << bitshift));
                }
@@ -197,87 +144,6 @@ static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw,
        RT_ASSERT(false, "deprecated!\n");
 }
 
-static u32 _phy_rf_serial_read(struct ieee80211_hw *hw,
-                              enum radio_path rfpath, u32 offset)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_phy *rtlphy = &(rtlpriv->phy);
-       struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
-       u32 newoffset;
-       u32 tmplong, tmplong2;
-       u8 rfpi_enable = 0;
-       u32 retvalue;
-
-       offset &= 0x3f;
-       newoffset = offset;
-       if (RT_CANNOT_IO(hw)) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
-               return 0xFFFFFFFF;
-       }
-       tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
-       if (rfpath == RF90_PATH_A)
-               tmplong2 = tmplong;
-       else
-               tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
-       tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
-           (newoffset << 23) | BLSSIREADEDGE;
-       rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
-                     tmplong & (~BLSSIREADEDGE));
-       mdelay(1);
-       rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
-       mdelay(1);
-       rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
-                     tmplong | BLSSIREADEDGE);
-       mdelay(1);
-       if (rfpath == RF90_PATH_A)
-               rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
-                                                BIT(8));
-       else if (rfpath == RF90_PATH_B)
-               rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
-                                                BIT(8));
-       if (rfpi_enable)
-               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
-                                        BLSSIREADBACKDATA);
-       else
-               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
-                                        BLSSIREADBACKDATA);
-       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n",
-                rfpath, pphyreg->rf_rb, retvalue);
-       return retvalue;
-}
-
-static void _phy_rf_serial_write(struct ieee80211_hw *hw,
-                                enum radio_path rfpath, u32 offset, u32 data)
-{
-       u32 data_and_addr;
-       u32 newoffset;
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_phy *rtlphy = &(rtlpriv->phy);
-       struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
-
-       if (RT_CANNOT_IO(hw)) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
-               return;
-       }
-       offset &= 0x3f;
-       newoffset = offset;
-       data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
-       rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
-       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n",
-                rfpath, pphyreg->rf3wire_offset, data_and_addr);
-}
-
-static u32 _phy_calculate_bit_shift(u32 bitmask)
-{
-       u32 i;
-
-       for (i = 0; i <= 31; i++) {
-               if (((bitmask >> i) & 0x1) == 1)
-                       break;
-       }
-       return i;
-}
-
 static void _rtl8723ae_phy_bb_config_1t(struct ieee80211_hw *hw)
 {
        rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2);
@@ -307,7 +173,7 @@ bool rtl8723ae_phy_bb_config(struct ieee80211_hw *hw)
        u8 tmpu1b;
        u8 reg_hwparafile = 1;
 
-       _phy_init_bb_rf_reg_def(hw);
+       rtl8723_phy_init_bb_rf_reg_def(hw);
 
        /* 1. 0x28[1] = 1 */
        tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_PLL_CTRL);
@@ -412,18 +278,7 @@ static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype)
        phy_regarray_table = RTL8723EPHY_REG_1TARRAY;
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_reg_arraylen; i = i + 2) {
-                       if (phy_regarray_table[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_regarray_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_regarray_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_regarray_table[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_regarray_table[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_regarray_table[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_regarray_table[i]);
                        rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
                                      phy_regarray_table[i + 1]);
                        udelay(1);
@@ -585,18 +440,7 @@ static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype)
 
        if (configtype == BASEBAND_CONFIG_PHY_REG) {
                for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
-                       if (phy_regarray_table_pg[i] == 0xfe)
-                               mdelay(50);
-                       else if (phy_regarray_table_pg[i] == 0xfd)
-                               mdelay(5);
-                       else if (phy_regarray_table_pg[i] == 0xfc)
-                               mdelay(1);
-                       else if (phy_regarray_table_pg[i] == 0xfb)
-                               udelay(50);
-                       else if (phy_regarray_table_pg[i] == 0xfa)
-                               udelay(5);
-                       else if (phy_regarray_table_pg[i] == 0xf9)
-                               udelay(1);
+                       rtl_addr_delay(phy_regarray_table_pg[i]);
 
                        _st_pwrIdx_dfrate_off(hw, phy_regarray_table_pg[i],
                                              phy_regarray_table_pg[i + 1],
@@ -623,24 +467,9 @@ bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
        switch (rfpath) {
        case RF90_PATH_A:
                for (i = 0; i < radioa_arraylen; i = i + 2) {
-                       if (radioa_array_table[i] == 0xfe)
-                               mdelay(50);
-                       else if (radioa_array_table[i] == 0xfd)
-                               mdelay(5);
-                       else if (radioa_array_table[i] == 0xfc)
-                               mdelay(1);
-                       else if (radioa_array_table[i] == 0xfb)
-                               udelay(50);
-                       else if (radioa_array_table[i] == 0xfa)
-                               udelay(5);
-                       else if (radioa_array_table[i] == 0xf9)
-                               udelay(1);
-                       else {
-                               rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
-                                             RFREG_OFFSET_MASK,
-                                             radioa_array_table[i + 1]);
-                               udelay(1);
-                       }
+                       rtl_rfreg_delay(hw, rfpath, radioa_array_table[i],
+                                       RFREG_OFFSET_MASK,
+                                       radioa_array_table[i + 1]);
                }
                break;
        case RF90_PATH_B:
@@ -690,92 +519,6 @@ void rtl8723ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
                 ROFDM0_RXDETECTOR3, rtlphy->framesync);
 }
 
-static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_phy *rtlphy = &(rtlpriv->phy);
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
-       rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
-       rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
-       rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB;
-       rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB;
-       rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
-       rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
-       rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
-       rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
-                           RFPGA0_XA_LSSIPARAMETER;
-       rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
-                           RFPGA0_XB_LSSIPARAMETER;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER;
-       rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER;
-       rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
-       rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
-       rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
-       rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
-       rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
-       rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
-       rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
-       rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
-       rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
-       rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2;
-       rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2;
-       rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
-       rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE;
-       rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
-       rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
-       rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
-       rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
-       rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
-       rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;
-       rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;
-
-       rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
-       rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
-}
-
 void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -785,17 +528,17 @@ void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
        long txpwr_dbm;
 
        txpwr_level = rtlphy->cur_cck_txpwridx;
-       txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, txpwr_level);
+       txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, txpwr_level);
        txpwr_level = rtlphy->cur_ofdm24g_txpwridx +
            rtlefuse->legacy_ht_txpowerdiff;
-       if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > txpwr_dbm)
-               txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+       if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > txpwr_dbm)
+               txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
                                                  txpwr_level);
        txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
-       if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, txpwr_level) >
+       if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, txpwr_level) >
            txpwr_dbm)
-               txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
-                                                 txpwr_level);
+               txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+                                                        txpwr_level);
        *powerlevel = txpwr_dbm;
 }
 
@@ -912,28 +655,6 @@ static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
        return txpwridx;
 }
 
-static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
-                                 enum wireless_mode wirelessmode, u8 txpwridx)
-{
-       long offset;
-       long pwrout_dbm;
-
-       switch (wirelessmode) {
-       case WIRELESS_MODE_B:
-               offset = -7;
-               break;
-       case WIRELESS_MODE_G:
-       case WIRELESS_MODE_N_24G:
-               offset = -8;
-               break;
-       default:
-               offset = -8;
-               break;
-       }
-       pwrout_dbm = txpwridx / 2 + offset;
-       return pwrout_dbm;
-}
-
 void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1117,26 +838,26 @@ static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
        u8 num_total_rfpath = rtlphy->num_total_rfpath;
 
        precommoncmdcnt = 0;
-       _phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
-                                 MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL,
-                                 0, 0, 0);
-       _phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
-                                 MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+       rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+                                        MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL,
+                                        0, 0, 0);
+       rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+                                        MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
        postcommoncmdcnt = 0;
 
-       _phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
-                                 MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+       rtl8723_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+                                        MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
        rfdependcmdcnt = 0;
 
        RT_ASSERT((channel >= 1 && channel <= 14),
                  "illegal channel for Zebra: %d\n", channel);
 
-       _phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
-                                 MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
+       rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+                                        MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
                                  RF_CHNLBW, channel, 10);
 
-       _phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
-                                 MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0);
+       rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+                                        MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0);
 
        do {
                switch (*stage) {
@@ -1204,29 +925,6 @@ static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
        return false;
 }
 
-static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
-                                     u32 cmdtableidx, u32 cmdtablesz,
-                                     enum swchnlcmd_id cmdid, u32 para1,
-                                     u32 para2, u32 msdelay)
-{
-       struct swchnlcmd *pcmd;
-
-       if (cmdtable == NULL) {
-               RT_ASSERT(false, "cmdtable cannot be NULL.\n");
-               return false;
-       }
-
-       if (cmdtableidx >= cmdtablesz)
-               return false;
-
-       pcmd = cmdtable + cmdtableidx;
-       pcmd->cmdid = cmdid;
-       pcmd->para1 = para1;
-       pcmd->para2 = para2;
-       pcmd->msdelay = msdelay;
-       return true;
-}
-
 static u8 _rtl8723ae_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
 {
        u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
@@ -1297,136 +995,6 @@ static u8 _rtl8723ae_phy_path_b_iqk(struct ieee80211_hw *hw)
        return result;
 }
 
-static void phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, bool iqk_ok,
-                                      long result[][8], u8 final_candidate,
-                                      bool btxonly)
-{
-       u32 oldval_0, x, tx0_a, reg;
-       long y, tx0_c;
-
-       if (final_candidate == 0xFF) {
-               return;
-       } else if (iqk_ok) {
-               oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
-                                         MASKDWORD) >> 22) & 0x3FF;
-               x = result[final_candidate][0];
-               if ((x & 0x00000200) != 0)
-                       x = x | 0xFFFFFC00;
-               tx0_a = (x * oldval_0) >> 8;
-               rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a);
-               rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31),
-                             ((x * oldval_0 >> 7) & 0x1));
-               y = result[final_candidate][1];
-               if ((y & 0x00000200) != 0)
-                       y = y | 0xFFFFFC00;
-               tx0_c = (y * oldval_0) >> 8;
-               rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
-                             ((tx0_c & 0x3C0) >> 6));
-               rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000,
-                             (tx0_c & 0x3F));
-               rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29),
-                             ((y * oldval_0 >> 7) & 0x1));
-               if (btxonly)
-                       return;
-               reg = result[final_candidate][2];
-               rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg);
-               reg = result[final_candidate][3] & 0x3F;
-               rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg);
-               reg = (result[final_candidate][3] >> 6) & 0xF;
-               rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg);
-       }
-}
-
-static void phy_save_adda_regs(struct ieee80211_hw *hw,
-                                              u32 *addareg, u32 *addabackup,
-                                              u32 registernum)
-{
-       u32 i;
-
-       for (i = 0; i < registernum; i++)
-               addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
-}
-
-static void phy_save_mac_regs(struct ieee80211_hw *hw, u32 *macreg,
-                             u32 *macbackup)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u32 i;
-
-       for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
-               macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]);
-       macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
-}
-
-static void phy_reload_adda_regs(struct ieee80211_hw *hw, u32 *addareg,
-                                u32 *addabackup, u32 regiesternum)
-{
-       u32 i;
-
-       for (i = 0; i < regiesternum; i++)
-               rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]);
-}
-
-static void phy_reload_mac_regs(struct ieee80211_hw *hw, u32 *macreg,
-                               u32 *macbackup)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u32 i;
-
-       for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
-               rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]);
-       rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
-}
-
-static void _rtl8723ae_phy_path_adda_on(struct ieee80211_hw *hw,
-                                       u32 *addareg, bool is_patha_on,
-                                       bool is2t)
-{
-       u32 pathOn;
-       u32 i;
-
-       pathOn = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
-       if (false == is2t) {
-               pathOn = 0x0bdb25a0;
-               rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
-       } else {
-               rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathOn);
-       }
-
-       for (i = 1; i < IQK_ADDA_REG_NUM; i++)
-               rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathOn);
-}
-
-static void _rtl8723ae_phy_mac_setting_calibration(struct ieee80211_hw *hw,
-                                                  u32 *macreg, u32 *macbackup)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u32 i = 0;
-
-       rtl_write_byte(rtlpriv, macreg[i], 0x3F);
-
-       for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
-               rtl_write_byte(rtlpriv, macreg[i],
-                              (u8) (macbackup[i] & (~BIT(3))));
-       rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5))));
-}
-
-static void _rtl8723ae_phy_path_a_standby(struct ieee80211_hw *hw)
-{
-       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
-       rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
-       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
-}
-
-static void _rtl8723ae_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode)
-{
-       u32 mode;
-
-       mode = pi_mode ? 0x01000100 : 0x01000000;
-       rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
-       rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
-}
-
 static bool phy_simularity_comp(struct ieee80211_hw *hw, long result[][8],
                                u8 c1, u8 c2)
 {
@@ -1498,10 +1066,12 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
        const u32 retrycount = 2;
 
        if (t == 0) {
-               phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
-               phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+               rtl8723_save_adda_registers(hw, adda_reg, rtlphy->adda_backup,
+                                           16);
+               rtl8723_phy_save_mac_registers(hw, iqk_mac_reg,
+                                              rtlphy->iqk_mac_backup);
        }
-       _rtl8723ae_phy_path_adda_on(hw, adda_reg, true, is2t);
+       rtl8723_phy_path_adda_on(hw, adda_reg, true, is2t);
        if (t == 0) {
                rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
                                                 RFPGA0_XA_HSSIPARAMETER1,
@@ -1509,7 +1079,7 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
        }
 
        if (!rtlphy->rfpi_enable)
-               _rtl8723ae_phy_pi_mode_switch(hw, true);
+               rtl8723_phy_pi_mode_switch(hw, true);
        if (t == 0) {
                rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD);
                rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD);
@@ -1522,7 +1092,7 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
                rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
                rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000);
        }
-       _rtl8723ae_phy_mac_setting_calibration(hw, iqk_mac_reg,
+       rtl8723_phy_mac_setting_calibration(hw, iqk_mac_reg,
                                            rtlphy->iqk_mac_backup);
        rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x00080000);
        if (is2t)
@@ -1552,8 +1122,8 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
        }
 
        if (is2t) {
-               _rtl8723ae_phy_path_a_standby(hw);
-               _rtl8723ae_phy_path_adda_on(hw, adda_reg, false, is2t);
+               rtl8723_phy_path_a_standby(hw);
+               rtl8723_phy_path_adda_on(hw, adda_reg, false, is2t);
                for (i = 0; i < retrycount; i++) {
                        pathb_ok = _rtl8723ae_phy_path_b_iqk(hw);
                        if (pathb_ok == 0x03) {
@@ -1588,9 +1158,11 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
                rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
        if (t != 0) {
                if (!rtlphy->rfpi_enable)
-                       _rtl8723ae_phy_pi_mode_switch(hw, false);
-               phy_reload_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
-               phy_reload_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+                       rtl8723_phy_pi_mode_switch(hw, false);
+               rtl8723_phy_reload_adda_registers(hw, adda_reg,
+                                                 rtlphy->adda_backup, 16);
+               rtl8723_phy_reload_mac_registers(hw, iqk_mac_reg,
+                                                rtlphy->iqk_mac_backup);
        }
 }
 
@@ -1691,7 +1263,8 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
        };
 
        if (recovery) {
-               phy_reload_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10);
+               rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg,
+                                                 rtlphy->iqk_bb_backup, 10);
                return;
        }
        if (start_conttx || singletone)
@@ -1756,9 +1329,10 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
                rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0;
        }
        if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
-               phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
-                                          final_candidate, (reg_ea4 == 0));
-       phy_save_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10);
+               rtl8723_phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
+                                                  final_candidate,
+                                                  (reg_ea4 == 0));
+       rtl8723_save_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10);
 }
 
 void rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw)
index 007ebdbbe108623f88c163e77d3e548eabc00eec..cd43139ed332abc85f656e8c766f5b680e5adeb1 100644 (file)
 
 #define RTL92C_MAX_PATH_NUM                    2
 
-enum swchnlcmd_id {
-       CMDID_END,
-       CMDID_SET_TXPOWEROWER_LEVEL,
-       CMDID_BBREGWRITE10,
-       CMDID_WRITEPORT_ULONG,
-       CMDID_WRITEPORT_USHORT,
-       CMDID_WRITEPORT_UCHAR,
-       CMDID_RF_WRITEREG,
-};
-
-struct swchnlcmd {
-       enum swchnlcmd_id cmdid;
-       u32 para1;
-       u32 para2;
-       u32 msdelay;
-};
-
 enum hw90_block_e {
        HW90_BLOCK_MAC = 0,
        HW90_BLOCK_PHY0 = 1,
@@ -183,10 +166,6 @@ struct tx_power_struct {
        u32 mcs_original_offset[4][16];
 };
 
-u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw,
-                              u32 regaddr, u32 bitmask);
-void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw,
-                             u32 regaddr, u32 bitmask, u32 data);
 u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
                               enum radio_path rfpath, u32 regaddr,
                               u32 bitmask);
index 7a46f9fdf558b08b5c60f2ddc758b2d9f7adfc4e..a418acb4d0ca1e56be786cc4122e4d8024dca33c 100644 (file)
@@ -30,7 +30,6 @@
 #ifndef __RTL8723E_PWRSEQ_H__
 #define __RTL8723E_PWRSEQ_H__
 
-#include "pwrseqcmd.h"
 /*
        Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd
        There are 6 HW Power States:
index 199da366c6da1a6b5a00dd03a14c8179f15026e9..64376b38708bd2e216f4b23a18da87247b4059b9 100644 (file)
 #define        BWORD1                                  0xc
 #define        BWORD                                   0xf
 
-#define        MASKBYTE0                               0xff
-#define        MASKBYTE1                               0xff00
-#define        MASKBYTE2                               0xff0000
-#define        MASKBYTE3                               0xff000000
-#define        MASKHWORD                               0xffff0000
-#define        MASKLWORD                               0x0000ffff
-#define        MASKDWORD                               0xffffffff
-#define        MASK12BITS                              0xfff
-#define        MASKH4BITS                              0xf0000000
-#define MASKOFDM_D                             0xffc00000
-#define        MASKCCK                                 0x3f3f3f3f
-
-#define        MASK4BITS                               0x0f
-#define        MASK20BITS                              0xfffff
-#define RFREG_OFFSET_MASK                      0xfffff
-
 #define        BENABLE                                 0x1
 #define        BDISABLE                                0x0
 
index 62b204faf773f74b1137aa2ada315375357268e8..1087a3bd07fa2dbd51f9983540ac44351374c58d 100644 (file)
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
+#include "../rtl8723com/phy_common.h"
 #include "dm.h"
 #include "hw.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
 #include "sw.h"
 #include "trx.h"
 #include "led.h"
@@ -193,6 +196,11 @@ void rtl8723ae_deinit_sw_vars(struct ieee80211_hw *hw)
        }
 }
 
+static bool is_fw_header(struct rtl92c_firmware_header *hdr)
+{
+       return (hdr->signature & 0xfff0) == 0x2300;
+}
+
 static struct rtl_hal_ops rtl8723ae_hal_ops = {
        .init_sw_vars = rtl8723ae_init_sw_vars,
        .deinit_sw_vars = rtl8723ae_deinit_sw_vars,
@@ -231,13 +239,14 @@ static struct rtl_hal_ops rtl8723ae_hal_ops = {
        .set_key = rtl8723ae_set_key,
        .init_sw_leds = rtl8723ae_init_sw_leds,
        .allow_all_destaddr = rtl8723ae_allow_all_destaddr,
-       .get_bbreg = rtl8723ae_phy_query_bb_reg,
-       .set_bbreg = rtl8723ae_phy_set_bb_reg,
+       .get_bbreg = rtl8723_phy_query_bb_reg,
+       .set_bbreg = rtl8723_phy_set_bb_reg,
        .get_rfreg = rtl8723ae_phy_query_rf_reg,
        .set_rfreg = rtl8723ae_phy_set_rf_reg,
        .c2h_command_handle = rtl_8723e_c2h_command_handle,
        .bt_wifi_media_status_notify = rtl_8723e_bt_wifi_media_status_notify,
        .bt_coex_off_before_lps = rtl8723ae_bt_coex_off_before_lps,
+       .is_fw_header = is_fw_header,
 };
 
 static struct rtl_mod_params rtl8723ae_mod_params = {
index 721162cacc3a2009fa4a4a9e8f003a4a492fbd94..29adf55c6fd37b9597e97d95a5ecf80fece7d3a1 100644 (file)
@@ -365,7 +365,7 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
 
 void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
                            struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-                           struct ieee80211_tx_info *info,
+                           u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                            struct ieee80211_sta *sta,
                            struct sk_buff *skb, u8 hw_queue,
                            struct rtl_tcb_desc *ptcdesc)
@@ -597,7 +597,8 @@ void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
                      pdesc, TX_DESC_SIZE);
 }
 
-void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                       u8 desc_name, u8 *val)
 {
        if (istx == true) {
                switch (desc_name) {
index ad05b54bc0f1b50d3f03d5b39cb4f6eff351717d..4380b7d3a91ac39c05e192816314bfaa4d4a6bc8 100644 (file)
@@ -521,12 +521,6 @@ do {                                                       \
                memset(__pdesc, 0, _size);              \
 } while (0)
 
-#define RTL8723E_RX_HAL_IS_CCK_RATE(rxmcs)             \
-       ((rxmcs) == DESC92_RATE1M ||                    \
-        (rxmcs) == DESC92_RATE2M ||                    \
-        (rxmcs) == DESC92_RATE5_5M ||                  \
-        (rxmcs) == DESC92_RATE11M)
-
 struct rx_fwinfo_8723e {
        u8 gain_trsw[4];
        u8 pwdb_all;
@@ -706,8 +700,8 @@ struct rx_desc_8723e {
 } __packed;
 
 void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
-                           struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-                           struct ieee80211_tx_info *info,
+                           struct ieee80211_hdr *hdr, u8 *pdesc,
+                           u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
                            struct ieee80211_sta *sta,
                            struct sk_buff *skb, u8 hw_queue,
                            struct rtl_tcb_desc *ptcb_desc);
@@ -715,7 +709,8 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
                             struct rtl_stats *status,
                             struct ieee80211_rx_status *rx_status,
                             u8 *pdesc, struct sk_buff *skb);
-void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                       u8 desc_name, u8 *val);
 u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name);
 void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
 void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/Makefile b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile
new file mode 100644 (file)
index 0000000..59e416a
--- /dev/null
@@ -0,0 +1,19 @@
+obj-m := rtl8723be.o
+
+
+rtl8723be-objs :=              \
+               dm.o            \
+               fw.o            \
+               hw.o            \
+               led.o           \
+               phy.o           \
+               pwrseq.o        \
+               rf.o            \
+               sw.o            \
+               table.o         \
+               trx.o           \
+
+
+obj-$(CONFIG_RTL8723BE) += rtl8723be.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/def.h b/drivers/net/wireless/rtlwifi/rtl8723be/def.h
new file mode 100644 (file)
index 0000000..3c30b74
--- /dev/null
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_DEF_H__
+#define __RTL8723BE_DEF_H__
+
+#define HAL_RETRY_LIMIT_INFRA                          48
+#define HAL_RETRY_LIMIT_AP_ADHOC                       7
+
+#define RESET_DELAY_8185                               20
+
+#define RT_IBSS_INT_MASKS      (IMR_BCNINT | IMR_TBDOK | IMR_TBDER)
+#define RT_AC_INT_MASKS                (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK)
+
+#define NUM_OF_FIRMWARE_QUEUE                  10
+#define NUM_OF_PAGES_IN_FW                     0x100
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK             0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE             0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI             0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO             0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA           0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_CMD            0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT           0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH           0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_BCN            0x2
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB            0xA1
+
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM         0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM         0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM         0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM         0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM                0x00
+
+#define MAX_LINES_HWCONFIG_TXT                 1000
+#define MAX_BYTES_LINE_HWCONFIG_TXT            256
+
+#define SW_THREE_WIRE                          0
+#define HW_THREE_WIRE                          2
+
+#define BT_DEMO_BOARD                          0
+#define BT_QA_BOARD                            1
+#define BT_FPGA                                        2
+
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE                0
+#define HAL_PRIME_CHNL_OFFSET_LOWER            1
+#define HAL_PRIME_CHNL_OFFSET_UPPER            2
+
+#define MAX_H2C_QUEUE_NUM                      10
+
+#define RX_MPDU_QUEUE                          0
+#define RX_CMD_QUEUE                           1
+#define RX_MAX_QUEUE                           2
+#define AC2QUEUEID(_AC)                                (_AC)
+
+#define        C2H_RX_CMD_HDR_LEN                      8
+#define        GET_C2H_CMD_CMD_LEN(__prxhdr)           \
+       LE_BITS_TO_4BYTE((__prxhdr), 0, 16)
+#define        GET_C2H_CMD_ELEMENT_ID(__prxhdr)        \
+       LE_BITS_TO_4BYTE((__prxhdr), 16, 8)
+#define        GET_C2H_CMD_CMD_SEQ(__prxhdr)           \
+       LE_BITS_TO_4BYTE((__prxhdr), 24, 7)
+#define        GET_C2H_CMD_CONTINUE(__prxhdr)          \
+       LE_BITS_TO_4BYTE((__prxhdr), 31, 1)
+#define        GET_C2H_CMD_CONTENT(__prxhdr)           \
+       ((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN)
+
+#define        GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr)    \
+       LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8)
+#define        GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr)       \
+       LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8)
+#define        GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr)   \
+       LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16)
+#define        GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr)    \
+       LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5)
+#define        GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr)     \
+       LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1)
+#define        GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \
+       LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5)
+#define        GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr)       \
+       LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1)
+#define        GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr)      \
+       LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4)
+#define        GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr)       \
+       LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
+
+#define CHIP_BONDING_IDENTIFIER(_value)        (((_value)>>22)&0x3)
+#define        CHIP_BONDING_92C_1T2R           0x1
+
+#define CHIP_8723                      BIT(0)
+#define CHIP_8723B                     (BIT(1) | BIT(2))
+#define NORMAL_CHIP                    BIT(3)
+#define RF_TYPE_1T1R                   (~(BIT(4) | BIT(5) | BIT(6)))
+#define RF_TYPE_1T2R                   BIT(4)
+#define RF_TYPE_2T2R                   BIT(5)
+#define CHIP_VENDOR_UMC                        BIT(7)
+#define B_CUT_VERSION                  BIT(12)
+#define C_CUT_VERSION                  BIT(13)
+#define D_CUT_VERSION                  ((BIT(12) | BIT(13)))
+#define E_CUT_VERSION                  BIT(14)
+#define        RF_RL_ID                        (BIT(31) | BIT(30) | BIT(29) | BIT(28))
+
+/* MASK */
+#define IC_TYPE_MASK                   (BIT(0) | BIT(1) | BIT(2))
+#define CHIP_TYPE_MASK                 BIT(3)
+#define RF_TYPE_MASK                   (BIT(4) | BIT(5) | BIT(6))
+#define MANUFACTUER_MASK               BIT(7)
+#define ROM_VERSION_MASK               (BIT(11) | BIT(10) | BIT(9) | BIT(8))
+#define CUT_VERSION_MASK               (BIT(15) | BIT(14) | BIT(13) | BIT(12))
+
+/* Get element */
+#define GET_CVID_IC_TYPE(version)      ((version) & IC_TYPE_MASK)
+#define GET_CVID_CHIP_TYPE(version)    ((version) & CHIP_TYPE_MASK)
+#define GET_CVID_RF_TYPE(version)      ((version) & RF_TYPE_MASK)
+#define GET_CVID_MANUFACTUER(version)  ((version) & MANUFACTUER_MASK)
+#define GET_CVID_ROM_VERSION(version)  ((version) & ROM_VERSION_MASK)
+#define GET_CVID_CUT_VERSION(version)  ((version) & CUT_VERSION_MASK)
+
+#define IS_92C_SERIAL(version)   ((IS_81XXC(version) && IS_2T2R(version)) ?\
+                                                               true : false)
+#define IS_81XXC(version)      ((GET_CVID_IC_TYPE(version) == 0) ?\
+                                                       true : false)
+#define IS_8723_SERIES(version)        ((GET_CVID_IC_TYPE(version) == CHIP_8723) ?\
+                                                       true : false)
+#define IS_1T1R(version)       ((GET_CVID_RF_TYPE(version)) ? false : true)
+#define IS_1T2R(version)       ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R)\
+                                                       ? true : false)
+#define IS_2T2R(version)       ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R)\
+                                                       ? true : false)
+enum rf_optype {
+       RF_OP_BY_SW_3WIRE = 0,
+       RF_OP_BY_FW,
+       RF_OP_MAX
+};
+
+enum rf_power_state {
+       RF_ON,
+       RF_OFF,
+       RF_SLEEP,
+       RF_SHUT_DOWN,
+};
+
+enum power_save_mode {
+       POWER_SAVE_MODE_ACTIVE,
+       POWER_SAVE_MODE_SAVE,
+};
+
+enum power_polocy_config {
+       POWERCFG_MAX_POWER_SAVINGS,
+       POWERCFG_GLOBAL_POWER_SAVINGS,
+       POWERCFG_LOCAL_POWER_SAVINGS,
+       POWERCFG_LENOVO,
+};
+
+enum interface_select_pci {
+       INTF_SEL1_MINICARD = 0,
+       INTF_SEL0_PCIE = 1,
+       INTF_SEL2_RSV = 2,
+       INTF_SEL3_RSV = 3,
+};
+
+enum rtl_desc_qsel {
+       QSLT_BK = 0x2,
+       QSLT_BE = 0x0,
+       QSLT_VI = 0x5,
+       QSLT_VO = 0x7,
+       QSLT_BEACON = 0x10,
+       QSLT_HIGH = 0x11,
+       QSLT_MGNT = 0x12,
+       QSLT_CMD = 0x13,
+};
+
+enum rtl_desc8723e_rate {
+       DESC92C_RATE1M = 0x00,
+       DESC92C_RATE2M = 0x01,
+       DESC92C_RATE5_5M = 0x02,
+       DESC92C_RATE11M = 0x03,
+
+       DESC92C_RATE6M = 0x04,
+       DESC92C_RATE9M = 0x05,
+       DESC92C_RATE12M = 0x06,
+       DESC92C_RATE18M = 0x07,
+       DESC92C_RATE24M = 0x08,
+       DESC92C_RATE36M = 0x09,
+       DESC92C_RATE48M = 0x0a,
+       DESC92C_RATE54M = 0x0b,
+
+       DESC92C_RATEMCS0 = 0x0c,
+       DESC92C_RATEMCS1 = 0x0d,
+       DESC92C_RATEMCS2 = 0x0e,
+       DESC92C_RATEMCS3 = 0x0f,
+       DESC92C_RATEMCS4 = 0x10,
+       DESC92C_RATEMCS5 = 0x11,
+       DESC92C_RATEMCS6 = 0x12,
+       DESC92C_RATEMCS7 = 0x13,
+       DESC92C_RATEMCS8 = 0x14,
+       DESC92C_RATEMCS9 = 0x15,
+       DESC92C_RATEMCS10 = 0x16,
+       DESC92C_RATEMCS11 = 0x17,
+       DESC92C_RATEMCS12 = 0x18,
+       DESC92C_RATEMCS13 = 0x19,
+       DESC92C_RATEMCS14 = 0x1a,
+       DESC92C_RATEMCS15 = 0x1b,
+       DESC92C_RATEMCS15_SG = 0x1c,
+       DESC92C_RATEMCS32 = 0x20,
+};
+
+enum rx_packet_type {
+       NORMAL_RX,
+       TX_REPORT1,
+       TX_REPORT2,
+       HIS_REPORT,
+};
+
+struct phy_sts_cck_8723e_t {
+       u8 adc_pwdb_X[4];
+       u8 sq_rpt;
+       u8 cck_agc_rpt;
+};
+
+struct h2c_cmd_8723e {
+       u8 element_id;
+       u32 cmd_len;
+       u8 *p_cmdbuffer;
+};
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
new file mode 100644 (file)
index 0000000..736bfcb
--- /dev/null
@@ -0,0 +1,1325 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../base.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "../rtl8723com/dm_common.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
+#include "trx.h"
+#include "../btcoexist/rtl_btc.h"
+
+static const u32 ofdmswing_table[] = {
+       0x0b40002d, /* 0,  -15.0dB */
+       0x0c000030, /* 1,  -14.5dB */
+       0x0cc00033, /* 2,  -14.0dB */
+       0x0d800036, /* 3,  -13.5dB */
+       0x0e400039, /* 4,  -13.0dB */
+       0x0f00003c, /* 5,  -12.5dB */
+       0x10000040, /* 6,  -12.0dB */
+       0x11000044, /* 7,  -11.5dB */
+       0x12000048, /* 8,  -11.0dB */
+       0x1300004c, /* 9,  -10.5dB */
+       0x14400051, /* 10, -10.0dB */
+       0x15800056, /* 11, -9.5dB */
+       0x16c0005b, /* 12, -9.0dB */
+       0x18000060, /* 13, -8.5dB */
+       0x19800066, /* 14, -8.0dB */
+       0x1b00006c, /* 15, -7.5dB */
+       0x1c800072, /* 16, -7.0dB */
+       0x1e400079, /* 17, -6.5dB */
+       0x20000080, /* 18, -6.0dB */
+       0x22000088, /* 19, -5.5dB */
+       0x24000090, /* 20, -5.0dB */
+       0x26000098, /* 21, -4.5dB */
+       0x288000a2, /* 22, -4.0dB */
+       0x2ac000ab, /* 23, -3.5dB */
+       0x2d4000b5, /* 24, -3.0dB */
+       0x300000c0, /* 25, -2.5dB */
+       0x32c000cb, /* 26, -2.0dB */
+       0x35c000d7, /* 27, -1.5dB */
+       0x390000e4, /* 28, -1.0dB */
+       0x3c8000f2, /* 29, -0.5dB */
+       0x40000100, /* 30, +0dB */
+       0x43c0010f, /* 31, +0.5dB */
+       0x47c0011f, /* 32, +1.0dB */
+       0x4c000130, /* 33, +1.5dB */
+       0x50800142, /* 34, +2.0dB */
+       0x55400155, /* 35, +2.5dB */
+       0x5a400169, /* 36, +3.0dB */
+       0x5fc0017f, /* 37, +3.5dB */
+       0x65400195, /* 38, +4.0dB */
+       0x6b8001ae, /* 39, +4.5dB */
+       0x71c001c7, /* 40, +5.0dB */
+       0x788001e2, /* 41, +5.5dB */
+       0x7f8001fe  /* 42, +6.0dB */
+};
+
+static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = {
+       {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}, /*  0, -16.0dB */
+       {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /*  1, -15.5dB */
+       {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /*  2, -15.0dB */
+       {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /*  3, -14.5dB */
+       {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /*  4, -14.0dB */
+       {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /*  5, -13.5dB */
+       {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /*  6, -13.0dB */
+       {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /*  7, -12.5dB */
+       {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /*  8, -12.0dB */
+       {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /*  9, -11.5dB */
+       {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 10, -11.0dB */
+       {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 11, -10.5dB */
+       {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 12, -10.0dB */
+       {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 13, -9.5dB */
+       {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 14, -9.0dB */
+       {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 15, -8.5dB */
+       {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */
+       {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 17, -7.5dB */
+       {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 18, -7.0dB */
+       {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 19, -6.5dB */
+       {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 20, -6.0dB */
+       {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 21, -5.5dB */
+       {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 22, -5.0dB */
+       {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 23, -4.5dB */
+       {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 24, -4.0dB */
+       {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 25, -3.5dB */
+       {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 26, -3.0dB */
+       {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 27, -2.5dB */
+       {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 28, -2.0dB */
+       {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 29, -1.5dB */
+       {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 30, -1.0dB */
+       {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 31, -0.5dB */
+       {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}  /* 32, +0dB */
+};
+
+static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
+       {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}, /*  0, -16.0dB */
+       {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  1, -15.5dB */
+       {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  2, -15.0dB */
+       {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  3, -14.5dB */
+       {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  4, -14.0dB */
+       {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  5, -13.5dB */
+       {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  6, -13.0dB */
+       {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  7, -12.5dB */
+       {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /*  8, -12.0dB */
+       {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /*  9, -11.5dB */
+       {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 10, -11.0dB */
+       {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 11, -10.5dB */
+       {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 12, -10.0dB */
+       {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 13, -9.5dB */
+       {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 14, -9.0dB */
+       {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 15, -8.5dB */
+       {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */
+       {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 17, -7.5dB */
+       {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 18, -7.0dB */
+       {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 19, -6.5dB */
+       {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 20, -6.0dB */
+       {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 21, -5.5dB */
+       {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 22, -5.0dB */
+       {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 23, -4.5dB */
+       {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 24, -4.0dB */
+       {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 25, -3.5dB */
+       {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 26, -3.0dB */
+       {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 27, -2.5dB */
+       {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 28, -2.0dB */
+       {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 29, -1.5dB */
+       {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 30, -1.0dB */
+       {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 31, -0.5dB */
+       {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}  /* 32, +0dB */
+};
+
+static const u32 edca_setting_dl[PEER_MAX] = {
+       0xa44f,         /* 0 UNKNOWN */
+       0x5ea44f,       /* 1 REALTEK_90 */
+       0x5e4322,       /* 2 REALTEK_92SE */
+       0x5ea42b,       /* 3 BROAD */
+       0xa44f,         /* 4 RAL */
+       0xa630,         /* 5 ATH */
+       0x5ea630,       /* 6 CISCO */
+       0x5ea42b,       /* 7 MARVELL */
+};
+
+static const u32 edca_setting_ul[PEER_MAX] = {
+       0x5e4322,       /* 0 UNKNOWN */
+       0xa44f,         /* 1 REALTEK_90 */
+       0x5ea44f,       /* 2 REALTEK_92SE */
+       0x5ea32b,       /* 3 BROAD */
+       0x5ea422,       /* 4 RAL */
+       0x5ea322,       /* 5 ATH */
+       0x3ea430,       /* 6 CISCO */
+       0x5ea44f,       /* 7 MARV */
+};
+
+void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type,
+                                      u8 *pdirection, u32 *poutwrite_val)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+       u8 pwr_val = 0;
+       u8 ofdm_base = rtlpriv->dm.swing_idx_ofdm_base[RF90_PATH_A];
+       u8 ofdm_val = rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A];
+       u8 cck_base = rtldm->swing_idx_cck_base;
+       u8 cck_val = rtldm->swing_idx_cck;
+
+       if (type == 0) {
+               if (ofdm_val <= ofdm_base) {
+                       *pdirection = 1;
+                       pwr_val = ofdm_base - ofdm_val;
+               } else {
+                       *pdirection = 2;
+                       pwr_val = ofdm_val - ofdm_base;
+               }
+       } else if (type == 1) {
+               if (cck_val <= cck_base) {
+                       *pdirection = 1;
+                       pwr_val = cck_base - cck_val;
+               } else {
+                       *pdirection = 2;
+                       pwr_val = cck_val - cck_base;
+               }
+       }
+
+       if (pwr_val >= TXPWRTRACK_MAX_IDX && (*pdirection == 1))
+               pwr_val = TXPWRTRACK_MAX_IDX;
+
+       *poutwrite_val = pwr_val | (pwr_val << 8) |
+                       (pwr_val << 16) | (pwr_val << 24);
+}
+
+static void rtl8723be_dm_diginit(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+       dm_digtable->dig_enable_flag = true;
+       dm_digtable->cur_igvalue = rtl_get_bbreg(hw,
+               ROFDM0_XAAGCCORE1, 0x7f);
+       dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
+       dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
+       dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+       dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+       dm_digtable->rx_gain_max = DM_DIG_MAX;
+       dm_digtable->rx_gain_min = DM_DIG_MIN;
+       dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
+       dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
+       dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
+       dm_digtable->pre_cck_cca_thres = 0xff;
+       dm_digtable->cur_cck_cca_thres = 0x83;
+       dm_digtable->forbidden_igi = DM_DIG_MIN;
+       dm_digtable->large_fa_hit = 0;
+       dm_digtable->recover_cnt = 0;
+       dm_digtable->dig_min_0 = DM_DIG_MIN;
+       dm_digtable->dig_min_1 = DM_DIG_MIN;
+       dm_digtable->media_connect_0 = false;
+       dm_digtable->media_connect_1 = false;
+       rtlpriv->dm.dm_initialgain_enable = true;
+       dm_digtable->bt30_cur_igi = 0x32;
+}
+
+void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rate_adaptive *ra = &(rtlpriv->ra);
+
+       ra->ratr_state = DM_RATR_STA_INIT;
+       ra->pre_ratr_state = DM_RATR_STA_INIT;
+
+       if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+               rtlpriv->dm.useramask = true;
+       else
+               rtlpriv->dm.useramask = false;
+
+       ra->high_rssi_thresh_for_ra = 50;
+       ra->low_rssi_thresh_for_ra40m = 20;
+}
+
+static void rtl8723be_dm_init_txpower_tracking(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm.txpower_tracking = true;
+       rtlpriv->dm.txpower_track_control = true;
+       rtlpriv->dm.thermalvalue = 0;
+
+       rtlpriv->dm.ofdm_index[0] = 30;
+       rtlpriv->dm.cck_index = 20;
+
+       rtlpriv->dm.swing_idx_cck_base = rtlpriv->dm.cck_index;
+
+       rtlpriv->dm.swing_idx_ofdm_base[0] = rtlpriv->dm.ofdm_index[0];
+       rtlpriv->dm.delta_power_index[RF90_PATH_A] = 0;
+       rtlpriv->dm.delta_power_index_last[RF90_PATH_A] = 0;
+       rtlpriv->dm.power_index_offset[RF90_PATH_A] = 0;
+
+       RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                "  rtlpriv->dm.txpower_tracking = %d\n",
+                rtlpriv->dm.txpower_tracking);
+}
+
+static void rtl8723be_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm.crystal_cap = rtlpriv->efuse.crystalcap;
+       rtlpriv->dm.atc_status = rtl_get_bbreg(hw, ROFDM1_CFOTRACKING, 0x800);
+       rtlpriv->dm.cfo_threshold = CFO_THRESHOLD_XTAL;
+}
+
+void rtl8723be_dm_init(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+       rtl8723be_dm_diginit(hw);
+       rtl8723be_dm_init_rate_adaptive_mask(hw);
+       rtl8723_dm_init_edca_turbo(hw);
+       rtl8723_dm_init_dynamic_bb_powersaving(hw);
+       rtl8723_dm_init_dynamic_txpower(hw);
+       rtl8723be_dm_init_txpower_tracking(hw);
+       rtl8723be_dm_init_dynamic_atc_switch(hw);
+}
+
+static void rtl8723be_dm_find_minimum_rssi(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *rtl_dm_dig = &(rtlpriv->dm_digtable);
+       struct rtl_mac *mac = rtl_mac(rtlpriv);
+
+       /* Determine the minimum RSSI  */
+       if ((mac->link_state < MAC80211_LINKED) &&
+           (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
+               rtl_dm_dig->min_undec_pwdb_for_dm = 0;
+               RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+                        "Not connected to any\n");
+       }
+       if (mac->link_state >= MAC80211_LINKED) {
+               if (mac->opmode == NL80211_IFTYPE_AP ||
+                   mac->opmode == NL80211_IFTYPE_ADHOC) {
+                       rtl_dm_dig->min_undec_pwdb_for_dm =
+                           rtlpriv->dm.entry_min_undec_sm_pwdb;
+                       RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+                                "AP Client PWDB = 0x%lx\n",
+                                rtlpriv->dm.entry_min_undec_sm_pwdb);
+               } else {
+                       rtl_dm_dig->min_undec_pwdb_for_dm =
+                           rtlpriv->dm.undec_sm_pwdb;
+                       RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+                                "STA Default Port PWDB = 0x%x\n",
+                                rtl_dm_dig->min_undec_pwdb_for_dm);
+               }
+       } else {
+               rtl_dm_dig->min_undec_pwdb_for_dm =
+                               rtlpriv->dm.entry_min_undec_sm_pwdb;
+               RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+                        "AP Ext Port or disconnet PWDB = 0x%x\n",
+                        rtl_dm_dig->min_undec_pwdb_for_dm);
+       }
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "MinUndecoratedPWDBForDM =%d\n",
+                rtl_dm_dig->min_undec_pwdb_for_dm);
+}
+
+static void rtl8723be_dm_check_rssi_monitor(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_sta_info *drv_priv;
+       u8 h2c_parameter[3] = { 0 };
+       long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
+
+       /* AP & ADHOC & MESH */
+       spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+       list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+               if (drv_priv->rssi_stat.undec_sm_pwdb <
+                                               tmp_entry_min_pwdb)
+                       tmp_entry_min_pwdb =
+                               drv_priv->rssi_stat.undec_sm_pwdb;
+               if (drv_priv->rssi_stat.undec_sm_pwdb >
+                                               tmp_entry_max_pwdb)
+                       tmp_entry_max_pwdb =
+                               drv_priv->rssi_stat.undec_sm_pwdb;
+       }
+       spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+       /* If associated entry is found */
+       if (tmp_entry_max_pwdb != 0) {
+               rtlpriv->dm.entry_max_undec_sm_pwdb = tmp_entry_max_pwdb;
+               RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                        "EntryMaxPWDB = 0x%lx(%ld)\n",
+                        tmp_entry_max_pwdb, tmp_entry_max_pwdb);
+       } else {
+               rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
+       }
+       /* If associated entry is found */
+       if (tmp_entry_min_pwdb != 0xff) {
+               rtlpriv->dm.entry_min_undec_sm_pwdb = tmp_entry_min_pwdb;
+               RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                        "EntryMinPWDB = 0x%lx(%ld)\n",
+                        tmp_entry_min_pwdb, tmp_entry_min_pwdb);
+       } else {
+               rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
+       }
+       /* Indicate Rx signal strength to FW. */
+       if (rtlpriv->dm.useramask) {
+               h2c_parameter[2] = (u8) (rtlpriv->dm.undec_sm_pwdb & 0xFF);
+               h2c_parameter[1] = 0x20;
+               h2c_parameter[0] = 0;
+               rtl8723be_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter);
+       } else {
+               rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb);
+       }
+       rtl8723be_dm_find_minimum_rssi(hw);
+       rtlpriv->dm_digtable.rssi_val_min =
+               rtlpriv->dm_digtable.min_undec_pwdb_for_dm;
+}
+
+void rtl8723be_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->dm_digtable.cur_igvalue != current_igi) {
+               rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, current_igi);
+               if (rtlpriv->phy.rf_type != RF_1T1R)
+                       rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, current_igi);
+       }
+       rtlpriv->dm_digtable.pre_igvalue = rtlpriv->dm_digtable.cur_igvalue;
+       rtlpriv->dm_digtable.cur_igvalue = current_igi;
+}
+
+static void rtl8723be_dm_dig(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct dig_t *dm_digtable = &(rtlpriv->dm_digtable);
+       u8 dig_dynamic_min, dig_maxofmin;
+       bool firstconnect, firstdisconnect;
+       u8 dm_dig_max, dm_dig_min;
+       u8 current_igi = dm_digtable->cur_igvalue;
+       u8 offset;
+
+       /* AP, BT */
+       if (mac->act_scanning)
+               return;
+
+       dig_dynamic_min = dm_digtable->dig_min_0;
+       firstconnect = (mac->link_state >= MAC80211_LINKED) &&
+                       !dm_digtable->media_connect_0;
+       firstdisconnect = (mac->link_state < MAC80211_LINKED) &&
+                          dm_digtable->media_connect_0;
+
+       dm_dig_max = 0x5a;
+       dm_dig_min = DM_DIG_MIN;
+       dig_maxofmin = DM_DIG_MAX_AP;
+
+       if (mac->link_state >= MAC80211_LINKED) {
+               if ((dm_digtable->rssi_val_min + 10) > dm_dig_max)
+                       dm_digtable->rx_gain_max = dm_dig_max;
+               else if ((dm_digtable->rssi_val_min + 10) < dm_dig_min)
+                       dm_digtable->rx_gain_max = dm_dig_min;
+               else
+                       dm_digtable->rx_gain_max =
+                               dm_digtable->rssi_val_min + 10;
+
+               if (rtlpriv->dm.one_entry_only) {
+                       offset = 12;
+                       if (dm_digtable->rssi_val_min - offset < dm_dig_min)
+                               dig_dynamic_min = dm_dig_min;
+                       else if (dm_digtable->rssi_val_min - offset >
+                                                       dig_maxofmin)
+                               dig_dynamic_min = dig_maxofmin;
+                       else
+                               dig_dynamic_min =
+                                       dm_digtable->rssi_val_min - offset;
+               } else {
+                       dig_dynamic_min = dm_dig_min;
+               }
+       } else {
+               dm_digtable->rx_gain_max = dm_dig_max;
+               dig_dynamic_min = dm_dig_min;
+               RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n");
+       }
+
+       if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
+               if (dm_digtable->large_fa_hit != 3)
+                       dm_digtable->large_fa_hit++;
+               if (dm_digtable->forbidden_igi < current_igi) {
+                       dm_digtable->forbidden_igi = current_igi;
+                       dm_digtable->large_fa_hit = 1;
+               }
+
+               if (dm_digtable->large_fa_hit >= 3) {
+                       if ((dm_digtable->forbidden_igi + 1) >
+                            dm_digtable->rx_gain_max)
+                               dm_digtable->rx_gain_min =
+                                               dm_digtable->rx_gain_max;
+                       else
+                               dm_digtable->rx_gain_min =
+                                               dm_digtable->forbidden_igi + 1;
+                       dm_digtable->recover_cnt = 3600;
+               }
+       } else {
+               if (dm_digtable->recover_cnt != 0) {
+                       dm_digtable->recover_cnt--;
+               } else {
+                       if (dm_digtable->large_fa_hit < 3) {
+                               if ((dm_digtable->forbidden_igi - 1) <
+                                    dig_dynamic_min) {
+                                       dm_digtable->forbidden_igi =
+                                                       dig_dynamic_min;
+                                       dm_digtable->rx_gain_min =
+                                                       dig_dynamic_min;
+                               } else {
+                                       dm_digtable->forbidden_igi--;
+                                       dm_digtable->rx_gain_min =
+                                               dm_digtable->forbidden_igi + 1;
+                               }
+                       } else {
+                               dm_digtable->large_fa_hit = 0;
+                       }
+               }
+       }
+       if (dm_digtable->rx_gain_min > dm_digtable->rx_gain_max)
+               dm_digtable->rx_gain_min = dm_digtable->rx_gain_max;
+
+       if (mac->link_state >= MAC80211_LINKED) {
+               if (firstconnect) {
+                       if (dm_digtable->rssi_val_min <= dig_maxofmin)
+                               current_igi = dm_digtable->rssi_val_min;
+                       else
+                               current_igi = dig_maxofmin;
+
+                       dm_digtable->large_fa_hit = 0;
+               } else {
+                       if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2)
+                               current_igi += 4;
+                       else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1)
+                               current_igi += 2;
+                       else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0)
+                               current_igi -= 2;
+               }
+       } else {
+               if (firstdisconnect) {
+                       current_igi = dm_digtable->rx_gain_min;
+               } else {
+                       if (rtlpriv->falsealm_cnt.cnt_all > 10000)
+                               current_igi += 4;
+                       else if (rtlpriv->falsealm_cnt.cnt_all > 8000)
+                               current_igi += 2;
+                       else if (rtlpriv->falsealm_cnt.cnt_all < 500)
+                               current_igi -= 2;
+               }
+       }
+
+       if (current_igi > dm_digtable->rx_gain_max)
+               current_igi = dm_digtable->rx_gain_max;
+       else if (current_igi < dm_digtable->rx_gain_min)
+               current_igi = dm_digtable->rx_gain_min;
+
+       rtl8723be_dm_write_dig(hw, current_igi);
+       dm_digtable->media_connect_0 =
+               ((mac->link_state >= MAC80211_LINKED) ? true : false);
+       dm_digtable->dig_min_0 = dig_dynamic_min;
+}
+
+static void rtl8723be_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+       u32 ret_value;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+
+       rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 1);
+       rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 1);
+
+       ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE1_11N, MASKDWORD);
+       falsealm_cnt->cnt_fast_fsync_fail = ret_value & 0xffff;
+       falsealm_cnt->cnt_sb_search_fail = (ret_value & 0xffff0000) >> 16;
+
+       ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE2_11N, MASKDWORD);
+       falsealm_cnt->cnt_ofdm_cca = ret_value & 0xffff;
+       falsealm_cnt->cnt_parity_fail = (ret_value & 0xffff0000) >> 16;
+
+       ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE3_11N, MASKDWORD);
+       falsealm_cnt->cnt_rate_illegal = ret_value & 0xffff;
+       falsealm_cnt->cnt_crc8_fail = (ret_value & 0xffff0000) >> 16;
+
+       ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE4_11N, MASKDWORD);
+       falsealm_cnt->cnt_mcs_fail = ret_value & 0xffff;
+
+       falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
+                                     falsealm_cnt->cnt_rate_illegal +
+                                     falsealm_cnt->cnt_crc8_fail +
+                                     falsealm_cnt->cnt_mcs_fail +
+                                     falsealm_cnt->cnt_fast_fsync_fail +
+                                     falsealm_cnt->cnt_sb_search_fail;
+
+       rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(12), 1);
+       rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(14), 1);
+
+       ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_RST_11N, MASKBYTE0);
+       falsealm_cnt->cnt_cck_fail = ret_value;
+
+       ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_MSB_11N, MASKBYTE3);
+       falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
+
+       ret_value = rtl_get_bbreg(hw, DM_REG_CCK_CCA_CNT_11N, MASKDWORD);
+       falsealm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) |
+                                   ((ret_value & 0xff00) >> 8);
+
+       falsealm_cnt->cnt_all = falsealm_cnt->cnt_fast_fsync_fail +
+                               falsealm_cnt->cnt_sb_search_fail +
+                               falsealm_cnt->cnt_parity_fail +
+                               falsealm_cnt->cnt_rate_illegal +
+                               falsealm_cnt->cnt_crc8_fail +
+                               falsealm_cnt->cnt_mcs_fail +
+                               falsealm_cnt->cnt_cck_fail;
+
+       falsealm_cnt->cnt_cca_all = falsealm_cnt->cnt_ofdm_cca +
+                                   falsealm_cnt->cnt_cck_cca;
+
+       rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 1);
+       rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 0);
+       rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 1);
+       rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 0);
+
+       rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 0);
+       rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 0);
+
+       rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 0);
+       rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 2);
+
+       rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 0);
+       rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 2);
+
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+                "cnt_parity_fail = %d, cnt_rate_illegal = %d, "
+                "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+                falsealm_cnt->cnt_parity_fail,
+                falsealm_cnt->cnt_rate_illegal,
+                falsealm_cnt->cnt_crc8_fail,
+                falsealm_cnt->cnt_mcs_fail);
+
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+                "cnt_ofdm_fail = %x, cnt_cck_fail = %x,"
+                " cnt_all = %x\n",
+                falsealm_cnt->cnt_ofdm_fail,
+                falsealm_cnt->cnt_cck_fail,
+                falsealm_cnt->cnt_all);
+}
+
+static void rtl8723be_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+       /* 8723BE does not support ODM_BB_DYNAMIC_TXPWR*/
+       return;
+}
+
+static void rtl8723be_set_iqk_matrix(struct ieee80211_hw *hw, u8 ofdm_index,
+                                    u8 rfpath, long iqk_result_x,
+                                    long iqk_result_y)
+{
+       long ele_a = 0, ele_d, ele_c = 0, value32;
+
+       if (ofdm_index >= 43)
+               ofdm_index = 43 - 1;
+
+       ele_d = (ofdmswing_table[ofdm_index] & 0xFFC00000) >> 22;
+
+       if (iqk_result_x != 0) {
+               if ((iqk_result_x & 0x00000200) != 0)
+                       iqk_result_x = iqk_result_x | 0xFFFFFC00;
+               ele_a = ((iqk_result_x * ele_d) >> 8) & 0x000003FF;
+
+               if ((iqk_result_y & 0x00000200) != 0)
+                       iqk_result_y = iqk_result_y | 0xFFFFFC00;
+               ele_c = ((iqk_result_y * ele_d) >> 8) & 0x000003FF;
+
+               switch (rfpath) {
+               case RF90_PATH_A:
+                       value32 = (ele_d << 22) |
+                               ((ele_c & 0x3F) << 16) | ele_a;
+                       rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD,
+                                     value32);
+                       value32 = (ele_c & 0x000003C0) >> 6;
+                       rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, value32);
+                       value32 = ((iqk_result_x * ele_d) >> 7) & 0x01;
+                       rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24),
+                                     value32);
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               switch (rfpath) {
+               case RF90_PATH_A:
+                       rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD,
+                                     ofdmswing_table[ofdm_index]);
+                       rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, 0x00);
+                       rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), 0x00);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void rtl8723be_dm_tx_power_track_set_power(struct ieee80211_hw *hw,
+                                       enum pwr_track_control_method method,
+                                       u8 rfpath, u8 idx)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+       u8 swing_idx_ofdm_limit = 36;
+
+       if (method == TXAGC) {
+               rtl8723be_phy_set_txpower_level(hw, rtlphy->current_channel);
+       } else if (method == BBSWING) {
+               if (rtldm->swing_idx_cck >= CCK_TABLE_SIZE)
+                       rtldm->swing_idx_cck = CCK_TABLE_SIZE - 1;
+
+               if (!rtldm->cck_inch14) {
+                       rtl_write_byte(rtlpriv, 0xa22,
+                           cckswing_table_ch1ch13[rtldm->swing_idx_cck][0]);
+                       rtl_write_byte(rtlpriv, 0xa23,
+                           cckswing_table_ch1ch13[rtldm->swing_idx_cck][1]);
+                       rtl_write_byte(rtlpriv, 0xa24,
+                           cckswing_table_ch1ch13[rtldm->swing_idx_cck][2]);
+                       rtl_write_byte(rtlpriv, 0xa25,
+                           cckswing_table_ch1ch13[rtldm->swing_idx_cck][3]);
+                       rtl_write_byte(rtlpriv, 0xa26,
+                           cckswing_table_ch1ch13[rtldm->swing_idx_cck][4]);
+                       rtl_write_byte(rtlpriv, 0xa27,
+                           cckswing_table_ch1ch13[rtldm->swing_idx_cck][5]);
+                       rtl_write_byte(rtlpriv, 0xa28,
+                           cckswing_table_ch1ch13[rtldm->swing_idx_cck][6]);
+                       rtl_write_byte(rtlpriv, 0xa29,
+                           cckswing_table_ch1ch13[rtldm->swing_idx_cck][7]);
+               } else {
+                       rtl_write_byte(rtlpriv, 0xa22,
+                           cckswing_table_ch14[rtldm->swing_idx_cck][0]);
+                       rtl_write_byte(rtlpriv, 0xa23,
+                           cckswing_table_ch14[rtldm->swing_idx_cck][1]);
+                       rtl_write_byte(rtlpriv, 0xa24,
+                           cckswing_table_ch14[rtldm->swing_idx_cck][2]);
+                       rtl_write_byte(rtlpriv, 0xa25,
+                           cckswing_table_ch14[rtldm->swing_idx_cck][3]);
+                       rtl_write_byte(rtlpriv, 0xa26,
+                           cckswing_table_ch14[rtldm->swing_idx_cck][4]);
+                       rtl_write_byte(rtlpriv, 0xa27,
+                           cckswing_table_ch14[rtldm->swing_idx_cck][5]);
+                       rtl_write_byte(rtlpriv, 0xa28,
+                           cckswing_table_ch14[rtldm->swing_idx_cck][6]);
+                       rtl_write_byte(rtlpriv, 0xa29,
+                           cckswing_table_ch14[rtldm->swing_idx_cck][7]);
+               }
+
+               if (rfpath == RF90_PATH_A) {
+                       if (rtldm->swing_idx_ofdm[RF90_PATH_A] <
+                           swing_idx_ofdm_limit)
+                               swing_idx_ofdm_limit =
+                                       rtldm->swing_idx_ofdm[RF90_PATH_A];
+
+                       rtl8723be_set_iqk_matrix(hw,
+                               rtldm->swing_idx_ofdm[rfpath], rfpath,
+                               rtlphy->iqk_matrix[idx].value[0][0],
+                               rtlphy->iqk_matrix[idx].value[0][1]);
+               } else if (rfpath == RF90_PATH_B) {
+                       if (rtldm->swing_idx_ofdm[RF90_PATH_B] <
+                           swing_idx_ofdm_limit)
+                               swing_idx_ofdm_limit =
+                                       rtldm->swing_idx_ofdm[RF90_PATH_B];
+
+                       rtl8723be_set_iqk_matrix(hw,
+                               rtldm->swing_idx_ofdm[rfpath], rfpath,
+                               rtlphy->iqk_matrix[idx].value[0][4],
+                               rtlphy->iqk_matrix[idx].value[0][5]);
+               }
+       } else {
+               return;
+       }
+}
+
+static void txpwr_track_cb_therm(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct rtl_dm   *rtldm = rtl_dm(rtl_priv(hw));
+       u8 thermalvalue = 0, delta, delta_lck, delta_iqk;
+       u8 thermalvalue_avg_count = 0;
+       u32 thermalvalue_avg = 0;
+       int i = 0;
+
+       u8 ofdm_min_index = 6;
+       u8 index = 0;
+
+       char delta_swing_table_idx_tup_a[] = {
+               0, 0, 1, 2, 2, 2, 3, 3, 3, 4,  5,
+               5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10,
+               10, 11, 11, 12, 12, 13, 14, 15};
+       char delta_swing_table_idx_tdown_a[] = {
+               0, 0, 1, 2, 2, 2, 3, 3, 3, 4,  5,
+               5, 6, 6, 6, 6, 7, 7, 7, 8, 8,  9,
+               9, 10, 10, 11, 12, 13, 14, 15};
+
+       /*Initilization ( 7 steps in total)*/
+       rtlpriv->dm.txpower_trackinginit = true;
+       RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                "rtl8723be_dm_txpower_tracking"
+                "_callback_thermalmeter\n");
+
+       thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0xfc00);
+       if (!rtlpriv->dm.txpower_track_control || thermalvalue == 0 ||
+           rtlefuse->eeprom_thermalmeter == 0xFF)
+               return;
+       RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                "Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+                "eeprom_thermalmeter 0x%x\n",
+                thermalvalue, rtldm->thermalvalue,
+                rtlefuse->eeprom_thermalmeter);
+       /*3 Initialize ThermalValues of RFCalibrateInfo*/
+       if (!rtldm->thermalvalue) {
+               rtlpriv->dm.thermalvalue_lck = thermalvalue;
+               rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+       }
+
+       /*4 Calculate average thermal meter*/
+       rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermalvalue;
+       rtldm->thermalvalue_avg_index++;
+       if (rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_8723BE)
+               rtldm->thermalvalue_avg_index = 0;
+
+       for (i = 0; i < AVG_THERMAL_NUM_8723BE; i++) {
+               if (rtldm->thermalvalue_avg[i]) {
+                       thermalvalue_avg += rtldm->thermalvalue_avg[i];
+                       thermalvalue_avg_count++;
+               }
+       }
+
+       if (thermalvalue_avg_count)
+               thermalvalue = (u8)(thermalvalue_avg / thermalvalue_avg_count);
+
+       /* 5 Calculate delta, delta_LCK, delta_IQK.*/
+       delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
+               (thermalvalue - rtlpriv->dm.thermalvalue) :
+               (rtlpriv->dm.thermalvalue - thermalvalue);
+       delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ?
+                   (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
+                   (rtlpriv->dm.thermalvalue_lck - thermalvalue);
+       delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ?
+                   (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
+                   (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
+
+       RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                "Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+                "eeprom_thermalmeter 0x%x delta 0x%x "
+                "delta_lck 0x%x delta_iqk 0x%x\n",
+                thermalvalue, rtlpriv->dm.thermalvalue,
+                rtlefuse->eeprom_thermalmeter, delta, delta_lck, delta_iqk);
+       /* 6 If necessary, do LCK.*/
+       if (delta_lck >= IQK_THRESHOLD) {
+               rtlpriv->dm.thermalvalue_lck = thermalvalue;
+               rtl8723be_phy_lc_calibrate(hw);
+       }
+
+       /* 7 If necessary, move the index of
+        * swing table to adjust Tx power.
+        */
+       if (delta > 0 && rtlpriv->dm.txpower_track_control) {
+               delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+                       (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+                       (rtlefuse->eeprom_thermalmeter - thermalvalue);
+
+               if (delta >= TXSCALE_TABLE_SIZE)
+                       delta = TXSCALE_TABLE_SIZE - 1;
+               /* 7.1 Get the final CCK_index and
+                * OFDM_index for each swing table.
+                */
+               if (thermalvalue > rtlefuse->eeprom_thermalmeter) {
+                       rtldm->delta_power_index_last[RF90_PATH_A] =
+                                       rtldm->delta_power_index[RF90_PATH_A];
+                       rtldm->delta_power_index[RF90_PATH_A] =
+                                       delta_swing_table_idx_tup_a[delta];
+               } else {
+                       rtldm->delta_power_index_last[RF90_PATH_A] =
+                                       rtldm->delta_power_index[RF90_PATH_A];
+                       rtldm->delta_power_index[RF90_PATH_A] =
+                               -1 * delta_swing_table_idx_tdown_a[delta];
+               }
+
+               /* 7.2 Handle boundary conditions of index.*/
+               if (rtldm->delta_power_index[RF90_PATH_A] ==
+                   rtldm->delta_power_index_last[RF90_PATH_A])
+                       rtldm->power_index_offset[RF90_PATH_A] = 0;
+               else
+                       rtldm->power_index_offset[RF90_PATH_A] =
+                               rtldm->delta_power_index[RF90_PATH_A] -
+                               rtldm->delta_power_index_last[RF90_PATH_A];
+
+               rtldm->ofdm_index[0] =
+                       rtldm->swing_idx_ofdm_base[RF90_PATH_A] +
+                       rtldm->power_index_offset[RF90_PATH_A];
+               rtldm->cck_index = rtldm->swing_idx_cck_base +
+                                  rtldm->power_index_offset[RF90_PATH_A];
+
+               rtldm->swing_idx_cck = rtldm->cck_index;
+               rtldm->swing_idx_ofdm[0] = rtldm->ofdm_index[0];
+
+               if (rtldm->ofdm_index[0] > OFDM_TABLE_SIZE - 1)
+                       rtldm->ofdm_index[0] = OFDM_TABLE_SIZE - 1;
+               else if (rtldm->ofdm_index[0] < ofdm_min_index)
+                       rtldm->ofdm_index[0] = ofdm_min_index;
+
+               if (rtldm->cck_index > CCK_TABLE_SIZE - 1)
+                       rtldm->cck_index = CCK_TABLE_SIZE - 1;
+               else if (rtldm->cck_index < 0)
+                       rtldm->cck_index = 0;
+       } else {
+               rtldm->power_index_offset[RF90_PATH_A] = 0;
+       }
+
+       if ((rtldm->power_index_offset[RF90_PATH_A] != 0) &&
+           (rtldm->txpower_track_control)) {
+               rtldm->done_txpower = true;
+               if (thermalvalue > rtlefuse->eeprom_thermalmeter)
+                       rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0,
+                                                             index);
+               else
+                       rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0,
+                                                             index);
+
+               rtldm->swing_idx_cck_base = rtldm->swing_idx_cck;
+               rtldm->swing_idx_ofdm_base[RF90_PATH_A] =
+                                               rtldm->swing_idx_ofdm[0];
+               rtldm->thermalvalue = thermalvalue;
+       }
+
+       if (delta_iqk >= IQK_THRESHOLD) {
+               rtldm->thermalvalue_iqk = thermalvalue;
+               rtl8723be_phy_iq_calibrate(hw, false);
+       }
+
+       rtldm->txpowercount = 0;
+       RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "end\n");
+}
+
+void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       static u8 tm_trigger;
+
+       if (!rtlpriv->dm.txpower_tracking)
+               return;
+
+       if (!tm_trigger) {
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | BIT(16),
+                             0x03);
+               RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                        "Trigger 8723be Thermal Meter!!\n");
+               tm_trigger = 1;
+               return;
+       } else {
+               RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                        "Schedule TxPowerTracking !!\n");
+               txpwr_track_cb_therm(hw);
+               tm_trigger = 0;
+       }
+}
+
+static void rtl8723be_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rate_adaptive *ra = &(rtlpriv->ra);
+       struct ieee80211_sta *sta = NULL;
+       u32 low_rssithresh_for_ra = ra->low2high_rssi_thresh_for_ra40m;
+       u32 high_rssithresh_for_ra = ra->high_rssi_thresh_for_ra;
+       u8 go_up_gap = 5;
+
+       if (is_hal_stop(rtlhal)) {
+               RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+                        "driver is going to unload\n");
+               return;
+       }
+
+       if (!rtlpriv->dm.useramask) {
+               RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+                        "driver does not control rate adaptive mask\n");
+               return;
+       }
+
+       if (mac->link_state == MAC80211_LINKED &&
+           mac->opmode == NL80211_IFTYPE_STATION) {
+               switch (ra->pre_ratr_state) {
+               case DM_RATR_STA_MIDDLE:
+                       high_rssithresh_for_ra += go_up_gap;
+                       break;
+               case DM_RATR_STA_LOW:
+                       high_rssithresh_for_ra += go_up_gap;
+                       low_rssithresh_for_ra += go_up_gap;
+                       break;
+               default:
+                       break;
+               }
+
+               if (rtlpriv->dm.undec_sm_pwdb >
+                   (long)high_rssithresh_for_ra)
+                       ra->ratr_state = DM_RATR_STA_HIGH;
+               else if (rtlpriv->dm.undec_sm_pwdb >
+                        (long)low_rssithresh_for_ra)
+                       ra->ratr_state = DM_RATR_STA_MIDDLE;
+               else
+                       ra->ratr_state = DM_RATR_STA_LOW;
+
+               if (ra->pre_ratr_state != ra->ratr_state) {
+                       RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+                                "RSSI = %ld\n",
+                                rtlpriv->dm.undec_sm_pwdb);
+                       RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+                                "RSSI_LEVEL = %d\n", ra->ratr_state);
+                       RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+                                "PreState = %d, CurState = %d\n",
+                                ra->pre_ratr_state, ra->ratr_state);
+
+                       rcu_read_lock();
+                       sta = rtl_find_sta(hw, mac->bssid);
+                       if (sta)
+                               rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+                                                          ra->ratr_state);
+                       rcu_read_unlock();
+
+                       ra->pre_ratr_state = ra->ratr_state;
+               }
+       }
+}
+
+static bool rtl8723be_dm_is_edca_turbo_disable(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->cfg->ops->get_btc_status()) {
+               if (rtlpriv->btcoexist.btc_ops->btc_is_disable_edca_turbo(rtlpriv))
+                       return true;
+       }
+       if (rtlpriv->mac80211.mode == WIRELESS_MODE_B)
+               return true;
+
+       return false;
+}
+
+static void rtl8723be_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       static u64 last_txok_cnt;
+       static u64 last_rxok_cnt;
+       u64 cur_txok_cnt = 0;
+       u64 cur_rxok_cnt = 0;
+       u32 edca_be_ul = 0x6ea42b;
+       u32 edca_be_dl = 0x6ea42b;/*not sure*/
+       u32 edca_be = 0x5ea42b;
+       u32 iot_peer = 0;
+       bool is_cur_rdlstate;
+       bool last_is_cur_rdlstate = false;
+       bool bias_on_rx = false;
+       bool edca_turbo_on = false;
+
+       last_is_cur_rdlstate = rtlpriv->dm.is_cur_rdlstate;
+
+       cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
+       cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
+       iot_peer = rtlpriv->mac80211.vendor;
+       bias_on_rx = (iot_peer == PEER_RAL || iot_peer == PEER_ATH) ?
+                    true : false;
+       edca_turbo_on = ((!rtlpriv->dm.is_any_nonbepkts) &&
+                        (!rtlpriv->dm.disable_framebursting)) ?
+                        true : false;
+
+       if ((iot_peer == PEER_CISCO) &&
+           (mac->mode == WIRELESS_MODE_N_24G)) {
+               edca_be_dl = edca_setting_dl[iot_peer];
+               edca_be_ul = edca_setting_ul[iot_peer];
+       }
+       if (rtl8723be_dm_is_edca_turbo_disable(hw))
+               goto exit;
+
+       if (edca_turbo_on) {
+               if (bias_on_rx)
+                       is_cur_rdlstate = (cur_txok_cnt > cur_rxok_cnt * 4) ?
+                                         false : true;
+               else
+                       is_cur_rdlstate = (cur_rxok_cnt > cur_txok_cnt * 4) ?
+                                         true : false;
+
+               edca_be = (is_cur_rdlstate) ? edca_be_dl : edca_be_ul;
+               rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, edca_be);
+               rtlpriv->dm.is_cur_rdlstate = is_cur_rdlstate;
+               rtlpriv->dm.current_turbo_edca = true;
+       } else {
+               if (rtlpriv->dm.current_turbo_edca) {
+                       u8 tmp = AC0_BE;
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+                                                     (u8 *)(&tmp));
+               }
+               rtlpriv->dm.current_turbo_edca = false;
+       }
+
+exit:
+       rtlpriv->dm.is_any_nonbepkts = false;
+       last_txok_cnt = rtlpriv->stats.txbytesunicast;
+       last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void rtl8723be_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 cur_cck_cca_thresh;
+
+       if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+               if (rtlpriv->dm_digtable.rssi_val_min > 25) {
+                       cur_cck_cca_thresh = 0xcd;
+               } else if ((rtlpriv->dm_digtable.rssi_val_min <= 25) &&
+                          (rtlpriv->dm_digtable.rssi_val_min > 10)) {
+                       cur_cck_cca_thresh = 0x83;
+               } else {
+                       if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+                               cur_cck_cca_thresh = 0x83;
+                       else
+                               cur_cck_cca_thresh = 0x40;
+               }
+       } else {
+               if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+                       cur_cck_cca_thresh = 0x83;
+               else
+                       cur_cck_cca_thresh = 0x40;
+       }
+
+       if (rtlpriv->dm_digtable.cur_cck_cca_thres != cur_cck_cca_thresh)
+               rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, cur_cck_cca_thresh);
+
+       rtlpriv->dm_digtable.pre_cck_cca_thres = rtlpriv->dm_digtable.cur_cck_cca_thres;
+       rtlpriv->dm_digtable.cur_cck_cca_thres = cur_cck_cca_thresh;
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+                "CCK cca thresh hold =%x\n",
+                rtlpriv->dm_digtable.cur_cck_cca_thres);
+}
+
+static void rtl8723be_dm_dynamic_edcca(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 reg_c50, reg_c58;
+       bool fw_current_in_ps_mode = false;
+
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+                                     (u8 *)(&fw_current_in_ps_mode));
+       if (fw_current_in_ps_mode)
+               return;
+
+       reg_c50 = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+       reg_c58 = rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+
+       if (reg_c50 > 0x28 && reg_c58 > 0x28) {
+               if (!rtlpriv->rtlhal.pre_edcca_enable) {
+                       rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x03);
+                       rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x00);
+               }
+       } else if (reg_c50 < 0x25 && reg_c58 < 0x25) {
+               if (rtlpriv->rtlhal.pre_edcca_enable) {
+                       rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x7f);
+                       rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x7f);
+               }
+       }
+}
+
+static void rtl8723be_dm_dynamic_atc_switch(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+       u8 crystal_cap;
+       u32 packet_count;
+       int cfo_khz_a, cfo_khz_b, cfo_ave = 0, adjust_xtal = 0;
+       int cfo_ave_diff;
+
+       if (rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+               if (rtldm->atc_status == ATC_STATUS_OFF) {
+                       rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
+                                     ATC_STATUS_ON);
+                       rtldm->atc_status = ATC_STATUS_ON;
+               }
+               if (rtlpriv->cfg->ops->get_btc_status()) {
+                       if (!rtlpriv->btcoexist.btc_ops->btc_is_bt_disabled(rtlpriv)) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
+                                        "odm_DynamicATCSwitch(): Disable"
+                                        " CFO tracking for BT!!\n");
+                               return;
+                       }
+               }
+
+               if (rtldm->crystal_cap != rtlpriv->efuse.crystalcap) {
+                       rtldm->crystal_cap = rtlpriv->efuse.crystalcap;
+                       crystal_cap = rtldm->crystal_cap & 0x3f;
+                       rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+                                     (crystal_cap | (crystal_cap << 6)));
+               }
+       } else {
+               cfo_khz_a = (int)(rtldm->cfo_tail[0] * 3125) / 1280;
+               cfo_khz_b = (int)(rtldm->cfo_tail[1] * 3125) / 1280;
+               packet_count = rtldm->packet_count;
+
+               if (packet_count == rtldm->packet_count_pre)
+                       return;
+
+               rtldm->packet_count_pre = packet_count;
+
+               if (rtlpriv->phy.rf_type == RF_1T1R)
+                       cfo_ave = cfo_khz_a;
+               else
+                       cfo_ave = (int)(cfo_khz_a + cfo_khz_b) >> 1;
+
+               cfo_ave_diff = (rtldm->cfo_ave_pre >= cfo_ave) ?
+                              (rtldm->cfo_ave_pre - cfo_ave) :
+                              (cfo_ave - rtldm->cfo_ave_pre);
+
+               if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) {
+                       rtldm->large_cfo_hit = 1;
+                       return;
+               } else {
+                       rtldm->large_cfo_hit = 0;
+               }
+
+               rtldm->cfo_ave_pre = cfo_ave;
+
+               if (cfo_ave >= -rtldm->cfo_threshold &&
+                   cfo_ave <= rtldm->cfo_threshold && rtldm->is_freeze == 0) {
+                       if (rtldm->cfo_threshold == CFO_THRESHOLD_XTAL) {
+                               rtldm->cfo_threshold = CFO_THRESHOLD_XTAL + 10;
+                               rtldm->is_freeze = 1;
+                       } else {
+                               rtldm->cfo_threshold = CFO_THRESHOLD_XTAL;
+                       }
+               }
+
+               if (cfo_ave > rtldm->cfo_threshold && rtldm->crystal_cap < 0x3f)
+                       adjust_xtal = ((cfo_ave - CFO_THRESHOLD_XTAL) >> 1) + 1;
+               else if ((cfo_ave < -rtlpriv->dm.cfo_threshold) &&
+                                       rtlpriv->dm.crystal_cap > 0)
+                       adjust_xtal = ((cfo_ave + CFO_THRESHOLD_XTAL) >> 1) - 1;
+
+               if (adjust_xtal != 0) {
+                       rtldm->is_freeze = 0;
+                       rtldm->crystal_cap += adjust_xtal;
+
+                       if (rtldm->crystal_cap > 0x3f)
+                               rtldm->crystal_cap = 0x3f;
+                       else if (rtldm->crystal_cap < 0)
+                               rtldm->crystal_cap = 0;
+
+                       crystal_cap = rtldm->crystal_cap & 0x3f;
+                       rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+                                     (crystal_cap | (crystal_cap << 6)));
+               }
+
+               if (cfo_ave < CFO_THRESHOLD_ATC &&
+                   cfo_ave > -CFO_THRESHOLD_ATC) {
+                       if (rtldm->atc_status == ATC_STATUS_ON) {
+                               rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
+                                             ATC_STATUS_OFF);
+                               rtldm->atc_status = ATC_STATUS_OFF;
+                       }
+               } else {
+                       if (rtldm->atc_status == ATC_STATUS_OFF) {
+                               rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
+                                             ATC_STATUS_ON);
+                               rtldm->atc_status = ATC_STATUS_ON;
+                       }
+               }
+       }
+}
+
+static void rtl8723be_dm_common_info_self_update(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_sta_info *drv_priv;
+       u8 cnt = 0;
+
+       rtlpriv->dm.one_entry_only = false;
+
+       if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION &&
+           rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+               rtlpriv->dm.one_entry_only = true;
+               return;
+       }
+
+       if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
+           rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC ||
+           rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) {
+               spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+               list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+                       cnt++;
+               }
+               spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+               if (cnt == 1)
+                       rtlpriv->dm.one_entry_only = true;
+       }
+}
+
+void rtl8723be_dm_watchdog(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       bool fw_current_inpsmode = false;
+       bool fw_ps_awake = true;
+
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+                                     (u8 *)(&fw_current_inpsmode));
+
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
+                                     (u8 *)(&fw_ps_awake));
+
+       if (ppsc->p2p_ps_info.p2p_ps_mode)
+               fw_ps_awake = false;
+
+       if ((ppsc->rfpwr_state == ERFON) &&
+           ((!fw_current_inpsmode) && fw_ps_awake) &&
+           (!ppsc->rfchange_inprogress)) {
+               rtl8723be_dm_common_info_self_update(hw);
+               rtl8723be_dm_false_alarm_counter_statistics(hw);
+               rtl8723be_dm_check_rssi_monitor(hw);
+               rtl8723be_dm_dig(hw);
+               rtl8723be_dm_dynamic_edcca(hw);
+               rtl8723be_dm_cck_packet_detection_thresh(hw);
+               rtl8723be_dm_refresh_rate_adaptive_mask(hw);
+               rtl8723be_dm_check_edca_turbo(hw);
+               rtl8723be_dm_dynamic_atc_switch(hw);
+               rtl8723be_dm_check_txpower_tracking(hw);
+               rtl8723be_dm_dynamic_txpower(hw);
+               if (rtlpriv->cfg->ops->get_btc_status())
+                       rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv);
+       }
+       rtlpriv->dm.dbginfo.num_qry_beacon_pkt = 0;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h
new file mode 100644 (file)
index 0000000..c6c2f2a
--- /dev/null
@@ -0,0 +1,310 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef        __RTL8723BE_DM_H__
+#define __RTL8723BE_DM_H__
+
+#define        MAIN_ANT                0
+#define        AUX_ANT                 1
+#define        MAIN_ANT_CG_TRX         1
+#define        AUX_ANT_CG_TRX          0
+#define        MAIN_ANT_CGCS_RX        0
+#define        AUX_ANT_CGCS_RX         1
+
+#define        TXSCALE_TABLE_SIZE      30
+
+/*RF REG LIST*/
+#define        DM_REG_RF_MODE_11N                      0x00
+#define        DM_REG_RF_0B_11N                        0x0B
+#define        DM_REG_CHNBW_11N                        0x18
+#define        DM_REG_T_METER_11N                      0x24
+#define        DM_REG_RF_25_11N                        0x25
+#define        DM_REG_RF_26_11N                        0x26
+#define        DM_REG_RF_27_11N                        0x27
+#define        DM_REG_RF_2B_11N                        0x2B
+#define        DM_REG_RF_2C_11N                        0x2C
+#define        DM_REG_RXRF_A3_11N                      0x3C
+#define        DM_REG_T_METER_92D_11N                  0x42
+#define        DM_REG_T_METER_88E_11N                  0x42
+
+/*BB REG LIST*/
+/*PAGE 8 */
+#define        DM_REG_BB_CTRL_11N                      0x800
+#define        DM_REG_RF_PIN_11N                       0x804
+#define        DM_REG_PSD_CTRL_11N                     0x808
+#define        DM_REG_TX_ANT_CTRL_11N                  0x80C
+#define        DM_REG_BB_PWR_SAV5_11N                  0x818
+#define        DM_REG_CCK_RPT_FORMAT_11N               0x824
+#define        DM_REG_RX_DEFUALT_A_11N                 0x858
+#define        DM_REG_RX_DEFUALT_B_11N                 0x85A
+#define        DM_REG_BB_PWR_SAV3_11N                  0x85C
+#define        DM_REG_ANTSEL_CTRL_11N                  0x860
+#define        DM_REG_RX_ANT_CTRL_11N                  0x864
+#define        DM_REG_PIN_CTRL_11N                     0x870
+#define        DM_REG_BB_PWR_SAV1_11N                  0x874
+#define        DM_REG_ANTSEL_PATH_11N                  0x878
+#define        DM_REG_BB_3WIRE_11N                     0x88C
+#define        DM_REG_SC_CNT_11N                       0x8C4
+#define        DM_REG_PSD_DATA_11N                     0x8B4
+/*PAGE 9*/
+#define        DM_REG_ANT_MAPPING1_11N                 0x914
+#define        DM_REG_ANT_MAPPING2_11N                 0x918
+/*PAGE A*/
+#define        DM_REG_CCK_ANTDIV_PARA1_11N             0xA00
+#define        DM_REG_CCK_CCA_11N                      0xA0A
+#define        DM_REG_CCK_ANTDIV_PARA2_11N             0xA0C
+#define        DM_REG_CCK_ANTDIV_PARA3_11N             0xA10
+#define        DM_REG_CCK_ANTDIV_PARA4_11N             0xA14
+#define        DM_REG_CCK_FILTER_PARA1_11N             0xA22
+#define        DM_REG_CCK_FILTER_PARA2_11N             0xA23
+#define        DM_REG_CCK_FILTER_PARA3_11N             0xA24
+#define        DM_REG_CCK_FILTER_PARA4_11N             0xA25
+#define        DM_REG_CCK_FILTER_PARA5_11N             0xA26
+#define        DM_REG_CCK_FILTER_PARA6_11N             0xA27
+#define        DM_REG_CCK_FILTER_PARA7_11N             0xA28
+#define        DM_REG_CCK_FILTER_PARA8_11N             0xA29
+#define        DM_REG_CCK_FA_RST_11N                   0xA2C
+#define        DM_REG_CCK_FA_MSB_11N                   0xA58
+#define        DM_REG_CCK_FA_LSB_11N                   0xA5C
+#define        DM_REG_CCK_CCA_CNT_11N                  0xA60
+#define        DM_REG_BB_PWR_SAV4_11N                  0xA74
+/*PAGE B */
+#define        DM_REG_LNA_SWITCH_11N                   0xB2C
+#define        DM_REG_PATH_SWITCH_11N                  0xB30
+#define        DM_REG_RSSI_CTRL_11N                    0xB38
+#define        DM_REG_CONFIG_ANTA_11N                  0xB68
+#define        DM_REG_RSSI_BT_11N                      0xB9C
+/*PAGE C */
+#define        DM_REG_OFDM_FA_HOLDC_11N                0xC00
+#define        DM_REG_RX_PATH_11N                      0xC04
+#define        DM_REG_TRMUX_11N                        0xC08
+#define        DM_REG_OFDM_FA_RSTC_11N                 0xC0C
+#define        DM_REG_RXIQI_MATRIX_11N                 0xC14
+#define        DM_REG_TXIQK_MATRIX_LSB1_11N            0xC4C
+#define        DM_REG_IGI_A_11N                        0xC50
+#define        DM_REG_ANTDIV_PARA2_11N                 0xC54
+#define        DM_REG_IGI_B_11N                        0xC58
+#define        DM_REG_ANTDIV_PARA3_11N                 0xC5C
+#define        DM_REG_BB_PWR_SAV2_11N                  0xC70
+#define        DM_REG_RX_OFF_11N                       0xC7C
+#define        DM_REG_TXIQK_MATRIXA_11N                0xC80
+#define        DM_REG_TXIQK_MATRIXB_11N                0xC88
+#define        DM_REG_TXIQK_MATRIXA_LSB2_11N           0xC94
+#define        DM_REG_TXIQK_MATRIXB_LSB2_11N           0xC9C
+#define        DM_REG_RXIQK_MATRIX_LSB_11N             0xCA0
+#define        DM_REG_ANTDIV_PARA1_11N                 0xCA4
+#define        DM_REG_OFDM_FA_TYPE1_11N                0xCF0
+/*PAGE D */
+#define        DM_REG_OFDM_FA_RSTD_11N                 0xD00
+#define        DM_REG_OFDM_FA_TYPE2_11N                0xDA0
+#define        DM_REG_OFDM_FA_TYPE3_11N                0xDA4
+#define        DM_REG_OFDM_FA_TYPE4_11N                0xDA8
+/*PAGE E */
+#define        DM_REG_TXAGC_A_6_18_11N                 0xE00
+#define        DM_REG_TXAGC_A_24_54_11N                0xE04
+#define        DM_REG_TXAGC_A_1_MCS32_11N              0xE08
+#define        DM_REG_TXAGC_A_MCS0_3_11N               0xE10
+#define        DM_REG_TXAGC_A_MCS4_7_11N               0xE14
+#define        DM_REG_TXAGC_A_MCS8_11_11N              0xE18
+#define        DM_REG_TXAGC_A_MCS12_15_11N             0xE1C
+#define        DM_REG_FPGA0_IQK_11N                    0xE28
+#define        DM_REG_TXIQK_TONE_A_11N                 0xE30
+#define        DM_REG_RXIQK_TONE_A_11N                 0xE34
+#define        DM_REG_TXIQK_PI_A_11N                   0xE38
+#define        DM_REG_RXIQK_PI_A_11N                   0xE3C
+#define        DM_REG_TXIQK_11N                        0xE40
+#define        DM_REG_RXIQK_11N                        0xE44
+#define        DM_REG_IQK_AGC_PTS_11N                  0xE48
+#define        DM_REG_IQK_AGC_RSP_11N                  0xE4C
+#define        DM_REG_BLUETOOTH_11N                    0xE6C
+#define        DM_REG_RX_WAIT_CCA_11N                  0xE70
+#define        DM_REG_TX_CCK_RFON_11N                  0xE74
+#define        DM_REG_TX_CCK_BBON_11N                  0xE78
+#define        DM_REG_OFDM_RFON_11N                    0xE7C
+#define        DM_REG_OFDM_BBON_11N                    0xE80
+#define DM_REG_TX2RX_11N                       0xE84
+#define        DM_REG_TX2TX_11N                        0xE88
+#define        DM_REG_RX_CCK_11N                       0xE8C
+#define        DM_REG_RX_OFDM_11N                      0xED0
+#define        DM_REG_RX_WAIT_RIFS_11N                 0xED4
+#define        DM_REG_RX2RX_11N                        0xED8
+#define        DM_REG_STANDBY_11N                      0xEDC
+#define        DM_REG_SLEEP_11N                        0xEE0
+#define        DM_REG_PMPD_ANAEN_11N                   0xEEC
+
+/*MAC REG LIST*/
+#define        DM_REG_BB_RST_11N                       0x02
+#define        DM_REG_ANTSEL_PIN_11N                   0x4C
+#define        DM_REG_EARLY_MODE_11N                   0x4D0
+#define        DM_REG_RSSI_MONITOR_11N                 0x4FE
+#define        DM_REG_EDCA_VO_11N                      0x500
+#define        DM_REG_EDCA_VI_11N                      0x504
+#define        DM_REG_EDCA_BE_11N                      0x508
+#define        DM_REG_EDCA_BK_11N                      0x50C
+#define        DM_REG_TXPAUSE_11N                      0x522
+#define        DM_REG_RESP_TX_11N                      0x6D8
+#define        DM_REG_ANT_TRAIN_PARA1_11N              0x7b0
+#define        DM_REG_ANT_TRAIN_PARA2_11N              0x7b4
+
+/*DIG Related*/
+#define        DM_BIT_IGI_11N                          0x0000007F
+
+#define HAL_DM_DIG_DISABLE                     BIT(0)
+#define HAL_DM_HIPWR_DISABLE                   BIT(1)
+
+#define OFDM_TABLE_LENGTH                      43
+#define CCK_TABLE_LENGTH                       33
+
+#define OFDM_TABLE_SIZE                                37
+#define CCK_TABLE_SIZE                         33
+
+#define BW_AUTO_SWITCH_HIGH_LOW                        25
+#define BW_AUTO_SWITCH_LOW_HIGH                        30
+
+#define DM_DIG_THRESH_HIGH                     40
+#define DM_DIG_THRESH_LOW                      35
+
+#define DM_FALSEALARM_THRESH_LOW               400
+#define DM_FALSEALARM_THRESH_HIGH              1000
+
+#define DM_DIG_MAX                             0x3e
+#define DM_DIG_MIN                             0x1e
+
+#define DM_DIG_MAX_AP                          0x32
+#define DM_DIG_MIN_AP                          0x20
+
+#define DM_DIG_FA_UPPER                                0x3e
+#define DM_DIG_FA_LOWER                                0x1e
+#define DM_DIG_FA_TH0                          0x200
+#define DM_DIG_FA_TH1                          0x300
+#define DM_DIG_FA_TH2                          0x400
+
+#define DM_DIG_BACKOFF_MAX                     12
+#define DM_DIG_BACKOFF_MIN                     -4
+#define DM_DIG_BACKOFF_DEFAULT                 10
+
+#define RXPATHSELECTION_DIFF_TH                        18
+
+#define DM_RATR_STA_INIT                       0
+#define DM_RATR_STA_HIGH                       1
+#define DM_RATR_STA_MIDDLE                     2
+#define DM_RATR_STA_LOW                                3
+
+#define CTS2SELF_THVAL                         30
+#define REGC38_TH                              20
+
+#define TXHIGHPWRLEVEL_NORMAL                  0
+#define TXHIGHPWRLEVEL_LEVEL1                  1
+#define TXHIGHPWRLEVEL_LEVEL2                  2
+#define TXHIGHPWRLEVEL_BT1                     3
+#define TXHIGHPWRLEVEL_BT2                     4
+
+#define DM_TYPE_BYFW                           0
+#define DM_TYPE_BYDRIVER                       1
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2                74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1                67
+#define TXPWRTRACK_MAX_IDX                     6
+
+/* Dynamic ATC switch */
+#define ATC_STATUS_OFF                         0x0 /* enable */
+#define        ATC_STATUS_ON                           0x1 /* disable */
+#define        CFO_THRESHOLD_XTAL                      10 /* kHz */
+#define        CFO_THRESHOLD_ATC                       80 /* kHz */
+
+enum FAT_STATE {
+       FAT_NORMAL_STATE        = 0,
+       FAT_TRAINING_STATE      = 1,
+};
+
+enum tag_dynamic_init_gain_operation_type_definition {
+       DIG_TYPE_THRESH_HIGH    = 0,
+       DIG_TYPE_THRESH_LOW     = 1,
+       DIG_TYPE_BACKOFF        = 2,
+       DIG_TYPE_RX_GAIN_MIN    = 3,
+       DIG_TYPE_RX_GAIN_MAX    = 4,
+       DIG_TYPE_ENABLE         = 5,
+       DIG_TYPE_DISABLE        = 6,
+       DIG_OP_TYPE_MAX
+};
+
+enum dm_1r_cca_e {
+       CCA_1R          = 0,
+       CCA_2R          = 1,
+       CCA_MAX         = 2,
+};
+
+enum dm_rf_e {
+       RF_SAVE         = 0,
+       RF_NORMAL       = 1,
+       RF_MAX          = 2,
+};
+
+enum dm_sw_ant_switch_e {
+       ANS_ANTENNA_B   = 1,
+       ANS_ANTENNA_A   = 2,
+       ANS_ANTENNA_MAX = 3,
+};
+
+enum dm_dig_ext_port_alg_e {
+       DIG_EXT_PORT_STAGE_0    = 0,
+       DIG_EXT_PORT_STAGE_1    = 1,
+       DIG_EXT_PORT_STAGE_2    = 2,
+       DIG_EXT_PORT_STAGE_3    = 3,
+       DIG_EXT_PORT_STAGE_MAX  = 4,
+};
+
+enum dm_dig_connect_e {
+       DIG_STA_DISCONNECT      = 0,
+       DIG_STA_CONNECT         = 1,
+       DIG_STA_BEFORE_CONNECT  = 2,
+       DIG_MULTISTA_DISCONNECT = 3,
+       DIG_MULTISTA_CONNECT    = 4,
+       DIG_CONNECT_MAX
+};
+
+enum pwr_track_control_method {
+       BBSWING,
+       TXAGC
+};
+
+#define BT_RSSI_STATE_NORMAL_POWER      BIT_OFFSET_LEN_MASK_32(0, 1)
+#define BT_RSSI_STATE_AMDPU_OFF         BIT_OFFSET_LEN_MASK_32(1, 1)
+#define BT_RSSI_STATE_SPECIAL_LOW       BIT_OFFSET_LEN_MASK_32(2, 1)
+#define BT_RSSI_STATE_BG_EDCA_LOW       BIT_OFFSET_LEN_MASK_32(3, 1)
+#define BT_RSSI_STATE_TXPOWER_LOW       BIT_OFFSET_LEN_MASK_32(4, 1)
+
+void rtl8723be_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw, u8 *pdesc,
+                                       u32 mac_id);
+void rtl8723be_dm_ant_sel_statistics(struct ieee80211_hw *hw, u8 antsel_tr_mux,
+                                    u32 mac_id, u32 rx_pwdb_all);
+void rtl8723be_dm_fast_antenna_trainning_callback(unsigned long data);
+void rtl8723be_dm_init(struct ieee80211_hw *hw);
+void rtl8723be_dm_watchdog(struct ieee80211_hw *hw);
+void rtl8723be_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi);
+void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw);
+void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
+void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type,
+                                      u8 *pdirection, u32 *poutwrite_val);
+void rtl8723be_dm_init_edca_turbo(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
new file mode 100644 (file)
index 0000000..f856be6
--- /dev/null
@@ -0,0 +1,620 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
+
+static bool _rtl8723be_check_fw_read_last_h2c(struct ieee80211_hw *hw,
+                                             u8 boxnum)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 val_hmetfr;
+       bool result = false;
+
+       val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
+       if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
+               result = true;
+       return result;
+}
+
+static void _rtl8723be_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
+                                       u32 cmd_len, u8 *p_cmdbuffer)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 boxnum;
+       u16 box_reg = 0, box_extreg = 0;
+       u8 u1b_tmp;
+       bool isfw_read = false;
+       u8 buf_index = 0;
+       bool bwrite_sucess = false;
+       u8 wait_h2c_limit = 100;
+       u8 wait_writeh2c_limit = 100;
+       u8 boxcontent[4], boxextcontent[4];
+       u32 h2c_waitcounter = 0;
+       unsigned long flag;
+       u8 idx;
+
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
+
+       while (true) {
+               spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+               if (rtlhal->h2c_setinprogress) {
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                "H2C set in progress! Wait to set.."
+                                "element_id(%d).\n", element_id);
+
+                       while (rtlhal->h2c_setinprogress) {
+                               spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
+                                                      flag);
+                               h2c_waitcounter++;
+                               RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                        "Wait 100 us (%d times)...\n",
+                                        h2c_waitcounter);
+                               udelay(100);
+
+                               if (h2c_waitcounter > 1000)
+                                       return;
+                               spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
+                                                 flag);
+                       }
+                       spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+               } else {
+                       rtlhal->h2c_setinprogress = true;
+                       spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+                       break;
+               }
+       }
+       while (!bwrite_sucess) {
+               wait_writeh2c_limit--;
+               if (wait_writeh2c_limit == 0) {
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "Write H2C fail because no trigger "
+                                "for FW INT!\n");
+                       break;
+               }
+               boxnum = rtlhal->last_hmeboxnum;
+               switch (boxnum) {
+               case 0:
+                       box_reg = REG_HMEBOX_0;
+                       box_extreg = REG_HMEBOX_EXT_0;
+                       break;
+               case 1:
+                       box_reg = REG_HMEBOX_1;
+                       box_extreg = REG_HMEBOX_EXT_1;
+                       break;
+               case 2:
+                       box_reg = REG_HMEBOX_2;
+                       box_extreg = REG_HMEBOX_EXT_2;
+                       break;
+               case 3:
+                       box_reg = REG_HMEBOX_3;
+                       box_extreg = REG_HMEBOX_EXT_3;
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not processed\n");
+                       break;
+               }
+               isfw_read = _rtl8723be_check_fw_read_last_h2c(hw, boxnum);
+               while (!isfw_read) {
+                       wait_h2c_limit--;
+                       if (wait_h2c_limit == 0) {
+                               RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                        "Wating too long for FW read "
+                                        "clear HMEBox(%d)!\n", boxnum);
+                               break;
+                       }
+                       udelay(10);
+
+                       isfw_read = _rtl8723be_check_fw_read_last_h2c(hw,
+                                                               boxnum);
+                       u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                "Wating for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
+                                boxnum, u1b_tmp);
+               }
+               if (!isfw_read) {
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                "Write H2C register BOX[%d] fail!!!!! "
+                                "Fw do not read.\n", boxnum);
+                       break;
+               }
+               memset(boxcontent, 0, sizeof(boxcontent));
+               memset(boxextcontent, 0, sizeof(boxextcontent));
+               boxcontent[0] = element_id;
+               RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                        "Write element_id box_reg(%4x) = %2x\n",
+                        box_reg, element_id);
+
+               switch (cmd_len) {
+               case 1:
+               case 2:
+               case 3:
+                       /*boxcontent[0] &= ~(BIT(7));*/
+                       memcpy((u8 *)(boxcontent) + 1,
+                              p_cmdbuffer + buf_index, cmd_len);
+
+                       for (idx = 0; idx < 4; idx++) {
+                               rtl_write_byte(rtlpriv, box_reg + idx,
+                                              boxcontent[idx]);
+                       }
+                       break;
+               case 4:
+               case 5:
+               case 6:
+               case 7:
+                       /*boxcontent[0] |= (BIT(7));*/
+                       memcpy((u8 *)(boxextcontent),
+                              p_cmdbuffer + buf_index+3, cmd_len-3);
+                       memcpy((u8 *)(boxcontent) + 1,
+                              p_cmdbuffer + buf_index, 3);
+
+                       for (idx = 0; idx < 4; idx++) {
+                               rtl_write_byte(rtlpriv, box_extreg + idx,
+                                              boxextcontent[idx]);
+                       }
+                       for (idx = 0; idx < 4; idx++) {
+                               rtl_write_byte(rtlpriv, box_reg + idx,
+                                              boxcontent[idx]);
+                       }
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not process\n");
+                       break;
+               }
+               bwrite_sucess = true;
+
+               rtlhal->last_hmeboxnum = boxnum + 1;
+               if (rtlhal->last_hmeboxnum == 4)
+                       rtlhal->last_hmeboxnum = 0;
+
+               RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                        "pHalData->last_hmeboxnum  = %d\n",
+                        rtlhal->last_hmeboxnum);
+       }
+       spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+       rtlhal->h2c_setinprogress = false;
+       spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
+}
+
+void rtl8723be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+                           u32 cmd_len, u8 *p_cmdbuffer)
+{
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u32 tmp_cmdbuf[2];
+
+       if (!rtlhal->fw_ready) {
+               RT_ASSERT(false,
+                         "return H2C cmd because of Fw download fail!!!\n");
+               return;
+       }
+       memset(tmp_cmdbuf, 0, 8);
+       memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
+       _rtl8723be_fill_h2c_command(hw, element_id, cmd_len,
+                                   (u8 *)&tmp_cmdbuf);
+       return;
+}
+
+void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 u1_h2c_set_pwrmode[H2C_8723BE_PWEMODE_LENGTH] = { 0 };
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       u8 rlbm, power_state = 0;
+       RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
+
+       SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
+       rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM = 2.*/
+       SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
+       SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+                                        (rtlpriv->mac80211.p2p) ?
+                                        ppsc->smart_ps : 1);
+       SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
+                                              ppsc->reg_max_lps_awakeintvl);
+       SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
+       if (mode == FW_PS_ACTIVE_MODE)
+               power_state |= FW_PWR_STATE_ACTIVE;
+       else
+               power_state |= FW_PWR_STATE_RF_OFF;
+       SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
+
+       RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+                     "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
+                     u1_h2c_set_pwrmode, H2C_8723BE_PWEMODE_LENGTH);
+       rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_SETPWRMODE,
+                              H2C_8723BE_PWEMODE_LENGTH,
+                              u1_h2c_set_pwrmode);
+}
+
+static bool _rtl8723be_cmd_send_packet(struct ieee80211_hw *hw,
+                                      struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl8192_tx_ring *ring;
+       struct rtl_tx_desc *pdesc;
+       struct sk_buff *pskb = NULL;
+       u8 own;
+       unsigned long flags;
+
+       ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+       pskb = __skb_dequeue(&ring->queue);
+       if (pskb)
+               kfree_skb(pskb);
+
+       spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+       pdesc = &ring->desc[0];
+       own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN);
+
+       rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
+
+       __skb_queue_tail(&ring->queue, skb);
+
+       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+       rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+       return true;
+}
+#define BEACON_PG              0 /* ->1 */
+#define PSPOLL_PG              2
+#define NULL_PG                        3
+#define PROBERSP_PG            4 /* ->5 */
+
+#define TOTAL_RESERVED_PKT_LEN 768
+
+static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
+       /* page 0 beacon */
+       0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
+       0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
+       0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
+       0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
+       0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
+       0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
+       0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
+       0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
+       0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
+       0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
+
+       /* page 1 beacon */
+       0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* page 2  ps-poll */
+       0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
+       0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* page 3  null */
+       0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
+       0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
+       0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* page 4  probe_resp */
+       0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+       0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+       0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+       0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
+       0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+       0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+       0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+       0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+       0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+       0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+       0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+       0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* page 5  probe_resp */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
+                                 bool dl_finished)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct sk_buff *skb = NULL;
+
+       u32 totalpacketlen;
+       bool rtstatus;
+       u8 u1rsvdpageloc[5] = { 0 };
+       bool dlok = false;
+
+       u8 *beacon;
+       u8 *p_pspoll;
+       u8 *nullfunc;
+       u8 *p_probersp;
+       /*---------------------------------------------------------
+        *                      (1) beacon
+        *---------------------------------------------------------
+        */
+       beacon = &reserved_page_packet[BEACON_PG * 128];
+       SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
+       SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
+
+       /*-------------------------------------------------------
+        *                      (2) ps-poll
+        *-------------------------------------------------------
+        */
+       p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+       SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
+       SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
+       SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
+
+       SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
+
+       /*--------------------------------------------------------
+        *                      (3) null data
+        *--------------------------------------------------------
+        */
+       nullfunc = &reserved_page_packet[NULL_PG * 128];
+       SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
+       SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
+       SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
+
+       SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
+
+       /*---------------------------------------------------------
+        *                      (4) probe response
+        *---------------------------------------------------------
+        */
+       p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
+       SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
+       SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
+       SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
+
+       SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
+
+       totalpacketlen = TOTAL_RESERVED_PKT_LEN;
+
+       RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+                     "rtl8723be_set_fw_rsvdpagepkt(): "
+                     "HW_VAR_SET_TX_CMD: ALL\n",
+                     &reserved_page_packet[0], totalpacketlen);
+       RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+                     "rtl8723be_set_fw_rsvdpagepkt(): "
+                     "HW_VAR_SET_TX_CMD: ALL\n", u1rsvdpageloc, 3);
+
+
+       skb = dev_alloc_skb(totalpacketlen);
+       memcpy((u8 *)skb_put(skb, totalpacketlen),
+              &reserved_page_packet, totalpacketlen);
+
+       rtstatus = _rtl8723be_cmd_send_packet(hw, skb);
+
+       if (rtstatus)
+               dlok = true;
+
+       if (dlok) {
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        "Set RSVD page location to Fw.\n");
+               RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "H2C_RSVDPAGE:\n",
+                             u1rsvdpageloc, 3);
+               rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_RSVDPAGE,
+                                      sizeof(u1rsvdpageloc), u1rsvdpageloc);
+       } else {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "Set RSVD page location to Fw FAIL!!!!!!.\n");
+       }
+}
+
+/*Should check FW support p2p or not.*/
+static void rtl8723be_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
+                                            u8 ctwindow)
+{
+       u8 u1_ctwindow_period[1] = {ctwindow};
+
+       rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_P2P_PS_CTW_CMD, 1,
+                              u1_ctwindow_period);
+}
+
+void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
+                                     u8 p2p_ps_state)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
+       struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+       u8 i;
+       u16 ctwindow;
+       u32 start_time, tsf_low;
+
+       switch (p2p_ps_state) {
+       case P2P_PS_DISABLE:
+               RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
+               memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+               break;
+       case P2P_PS_ENABLE:
+               RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
+               /* update CTWindow value. */
+               if (p2pinfo->ctwindow > 0) {
+                       p2p_ps_offload->ctwindow_en = 1;
+                       ctwindow = p2pinfo->ctwindow;
+                       rtl8723be_set_p2p_ctw_period_cmd(hw, ctwindow);
+               }
+               /* hw only support 2 set of NoA */
+               for (i = 0; i < p2pinfo->noa_num; i++) {
+                       /* To control the register setting
+                        * for which NOA
+                        */
+                       rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+                       if (i == 0)
+                               p2p_ps_offload->noa0_en = 1;
+                       else
+                               p2p_ps_offload->noa1_en = 1;
+
+                       /* config P2P NoA Descriptor Register */
+                       rtl_write_dword(rtlpriv, 0x5E0,
+                                       p2pinfo->noa_duration[i]);
+                       rtl_write_dword(rtlpriv, 0x5E4,
+                                       p2pinfo->noa_interval[i]);
+
+                       /*Get Current TSF value */
+                       tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+                       start_time = p2pinfo->noa_start_time[i];
+                       if (p2pinfo->noa_count_type[i] != 1) {
+                               while (start_time <= (tsf_low + (50 * 1024))) {
+                                       start_time += p2pinfo->noa_interval[i];
+                                       if (p2pinfo->noa_count_type[i] != 255)
+                                               p2pinfo->noa_count_type[i]--;
+                               }
+                       }
+                       rtl_write_dword(rtlpriv, 0x5E8, start_time);
+                       rtl_write_dword(rtlpriv, 0x5EC,
+                                       p2pinfo->noa_count_type[i]);
+               }
+               if ((p2pinfo->opp_ps == 1) ||
+                   (p2pinfo->noa_num > 0)) {
+                       /* rst p2p circuit */
+                       rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+
+                       p2p_ps_offload->offload_en = 1;
+
+                       if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+                               p2p_ps_offload->role = 1;
+                               p2p_ps_offload->allstasleep = 0;
+                       } else {
+                               p2p_ps_offload->role = 0;
+                       }
+                       p2p_ps_offload->discovery = 0;
+               }
+               break;
+       case P2P_PS_SCAN:
+               RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+               p2p_ps_offload->discovery = 1;
+               break;
+       case P2P_PS_SCAN_DONE:
+               RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
+               p2p_ps_offload->discovery = 0;
+               p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+               break;
+       default:
+               break;
+       }
+       rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_P2P_PS_OFFLOAD, 1,
+                              (u8 *)p2p_ps_offload);
+}
+
+void rtl8723be_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
+{
+       u8 u1_joinbssrpt_parm[1] = { 0 };
+
+       SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
+
+       rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_JOINBSSRPT, 1,
+                              u1_joinbssrpt_parm);
+}
+
+void rtl8723be_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
+                                     u8 ap_offload_enable)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u8 u1_apoffload_parm[H2C_8723BE_AP_OFFLOAD_LENGTH] = { 0 };
+
+       SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
+       SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
+       SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
+
+       rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_AP_OFFLOAD,
+                              H2C_8723BE_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.h b/drivers/net/wireless/rtlwifi/rtl8723be/fw.h
new file mode 100644 (file)
index 0000000..31eec28
--- /dev/null
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE__FW__H__
+#define __RTL8723BE__FW__H__
+
+#define FW_8192C_SIZE                          0x8000
+#define FW_8192C_START_ADDRESS                 0x1000
+#define FW_8192C_END_ADDRESS                   0x5FFF
+#define FW_8192C_PAGE_SIZE                     4096
+#define FW_8192C_POLLING_DELAY                 5
+#define FW_8192C_POLLING_TIMEOUT_COUNT         6000
+
+#define IS_FW_HEADER_EXIST(_pfwhdr)    \
+       ((_pfwhdr->signature&0xFFF0) == 0x5300)
+#define USE_OLD_WOWLAN_DEBUG_FW                        0
+
+#define H2C_8723BE_RSVDPAGE_LOC_LEN            5
+#define H2C_8723BE_PWEMODE_LENGTH              5
+#define H2C_8723BE_JOINBSSRPT_LENGTH           1
+#define H2C_8723BE_AP_OFFLOAD_LENGTH           3
+#define H2C_8723BE_WOWLAN_LENGTH               3
+#define H2C_8723BE_KEEP_ALIVE_CTRL_LENGTH      3
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define H2C_8723BE_REMOTE_WAKE_CTRL_LEN                1
+#else
+#define H2C_8723BE_REMOTE_WAKE_CTRL_LEN                3
+#endif
+#define H2C_8723BE_AOAC_GLOBAL_INFO_LEN                2
+#define H2C_8723BE_AOAC_RSVDPAGE_LOC_LEN       7
+
+
+/* Fw PS state for RPWM.
+*BIT[2:0] = HW state
+*BIT[3] = Protocol PS state, 1: register active state , 0: register sleep state
+*BIT[4] = sub-state
+*/
+#define        FW_PS_GO_ON             BIT(0)
+#define        FW_PS_TX_NULL           BIT(1)
+#define        FW_PS_RF_ON             BIT(2)
+#define        FW_PS_REGISTER_ACTIVE   BIT(3)
+
+#define        FW_PS_DPS               BIT(0)
+#define        FW_PS_LCLK              (FW_PS_DPS)
+#define        FW_PS_RF_OFF            BIT(1)
+#define        FW_PS_ALL_ON            BIT(2)
+#define        FW_PS_ST_ACTIVE BIT(3)
+#define        FW_PS_ISR_ENABLE        BIT(4)
+#define        FW_PS_IMR_ENABLE        BIT(5)
+
+
+#define        FW_PS_ACK               BIT(6)
+#define        FW_PS_TOGGLE            BIT(7)
+
+ /* 88E RPWM value*/
+ /* BIT[0] = 1: 32k, 0: 40M*/
+#define        FW_PS_CLOCK_OFF         BIT(0)          /* 32k*/
+#define        FW_PS_CLOCK_ON          0               /*40M*/
+
+#define        FW_PS_STATE_MASK        (0x0F)
+#define        FW_PS_STATE_HW_MASK     (0x07)
+/*ISR_ENABLE, IMR_ENABLE, and PS mode should be inherited.*/
+#define        FW_PS_STATE_INT_MASK    (0x3F)
+
+#define        FW_PS_STATE(x)  (FW_PS_STATE_MASK & (x))
+#define        FW_PS_STATE_HW(x)       (FW_PS_STATE_HW_MASK & (x))
+#define        FW_PS_STATE_INT(x)      (FW_PS_STATE_INT_MASK & (x))
+#define        FW_PS_ISR_VAL(x)        ((x) & 0x70)
+#define        FW_PS_IMR_MASK(x)       ((x) & 0xDF)
+#define        FW_PS_KEEP_IMR(x)       ((x) & 0x20)
+
+
+#define        FW_PS_STATE_S0          (FW_PS_DPS)
+#define        FW_PS_STATE_S1          (FW_PS_LCLK)
+#define        FW_PS_STATE_S2          (FW_PS_RF_OFF)
+#define        FW_PS_STATE_S3          (FW_PS_ALL_ON)
+#define        FW_PS_STATE_S4          ((FW_PS_ST_ACTIVE) | (FW_PS_ALL_ON))
+
+/* ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))*/
+#define        FW_PS_STATE_ALL_ON_88E  (FW_PS_CLOCK_ON)
+/* (FW_PS_RF_ON)*/
+#define        FW_PS_STATE_RF_ON_88E   (FW_PS_CLOCK_ON)
+/* 0x0*/
+#define        FW_PS_STATE_RF_OFF_88E  (FW_PS_CLOCK_ON)
+/* (FW_PS_STATE_RF_OFF)*/
+#define        FW_PS_STATE_RF_OFF_LOW_PWR_88E  (FW_PS_CLOCK_OFF)
+
+#define        FW_PS_STATE_ALL_ON_92C  (FW_PS_STATE_S4)
+#define        FW_PS_STATE_RF_ON_92C           (FW_PS_STATE_S3)
+#define        FW_PS_STATE_RF_OFF_92C  (FW_PS_STATE_S2)
+#define        FW_PS_STATE_RF_OFF_LOW_PWR_92C  (FW_PS_STATE_S1)
+
+
+/* For 88E H2C PwrMode Cmd ID 5.*/
+#define        FW_PWR_STATE_ACTIVE     ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define        FW_PWR_STATE_RF_OFF     0
+
+#define        FW_PS_IS_ACK(x) ((x) & FW_PS_ACK)
+#define        FW_PS_IS_CLK_ON(x)      ((x) & (FW_PS_RF_OFF | FW_PS_ALL_ON))
+#define        FW_PS_IS_RF_ON(x)       ((x) & (FW_PS_ALL_ON))
+#define        FW_PS_IS_ACTIVE(x)      ((x) & (FW_PS_ST_ACTIVE))
+#define        FW_PS_IS_CPWM_INT(x)    ((x) & 0x40)
+
+#define        FW_CLR_PS_STATE(x)      ((x) = ((x) & (0xF0)))
+
+#define        IS_IN_LOW_POWER_STATE_88E(fwpsstate)            \
+                       (FW_PS_STATE(fwpsstate) == FW_PS_CLOCK_OFF)
+
+#define        FW_PWR_STATE_ACTIVE     ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define        FW_PWR_STATE_RF_OFF     0
+
+#define pagenum_128(_len)      (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
+
+#define SET_88E_H2CCMD_WOWLAN_FUNC_ENABLE(__ph2ccmd, __val)            \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__ph2ccmd, __val)   \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(__ph2ccmd, __val)       \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 2, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(__ph2ccmd, __val)     \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 3, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_ALL_PKT_DROP(__ph2ccmd, __val)           \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 4, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_GPIO_ACTIVE(__ph2ccmd, __val)            \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 5, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_REKEY_WAKE_UP(__ph2ccmd, __val)          \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 6, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(__ph2ccmd, __val)     \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 7, 1, __val)
+#define SET_88E_H2CCMD_WOWLAN_GPIONUM(__ph2ccmd, __val)                        \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_88E_H2CCMD_WOWLAN_GPIO_DURATION(__ph2ccmd, __val)          \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+
+
+#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)                 \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_RLBM(__ph2ccmd, __val)                 \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 4, __val)
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val)             \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 4, 4, __val)
+#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__ph2ccmd, __val)       \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__ph2ccmd, __val)      \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__ph2ccmd, __val)            \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+4, 0, 8, __val)
+#define GET_88E_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd)                    \
+       LE_BITS_TO_1BYTE(__ph2ccmd, 0, 8)
+
+#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val)            \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val)            \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val)               \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)            \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+
+/* AP_OFFLOAD */
+#define SET_H2CCMD_AP_OFFLOAD_ON(__ph2ccmd, __val)                     \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_AP_OFFLOAD_HIDDEN(__ph2ccmd, __val)                 \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_AP_OFFLOAD_DENYANY(__ph2ccmd, __val)                        \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#define SET_H2CCMD_AP_OFFLOAD_WAKEUP_EVT_RPT(__ph2ccmd, __val)         \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val)
+
+/* Keep Alive Control*/
+#define SET_88E_H2CCMD_KEEP_ALIVE_ENABLE(__ph2ccmd, __val)             \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
+#define SET_88E_H2CCMD_KEEP_ALIVE_ACCPEPT_USER_DEFINED(__ph2ccmd, __val)\
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
+#define SET_88E_H2CCMD_KEEP_ALIVE_PERIOD(__ph2ccmd, __val)             \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+
+/*REMOTE_WAKE_CTRL */
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_EN(__ph2ccmd, __val)           \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(__ph2ccmd, __val)\
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN(__ph2ccmd, __val)\
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 2, 1, __val)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(__ph2ccmd, __val)\
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 3, 1, __val)
+#else
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_PAIRWISE_ENC_ALG(__ph2ccmd, __val)\
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GROUP_ENC_ALG(__ph2ccmd, __val)        \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#endif
+
+/* GTK_OFFLOAD */
+#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(__ph2ccmd, __val)\
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(__ph2ccmd, __val)        \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+
+/* AOAC_RSVDPAGE_LOC */
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_REM_WAKE_CTRL_INFO(__ph2ccmd, __val)\
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd), 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__ph2ccmd, __val)     \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__ph2ccmd, __val)        \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__ph2ccmd, __val)     \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__ph2ccmd, __val)    \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+4, 0, 8, __val)
+
+void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl8723be_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
+                                     u8 ap_offload_enable);
+void rtl8723be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+                           u32 cmd_len, u8 *p_cmdbuffer);
+void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
+                                 bool dl_finished);
+void rtl8723be_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
+int rtl8723be_download_fw(struct ieee80211_hw *hw,
+                         bool buse_wake_on_wlan_fw);
+void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
+                                     u8 p2p_ps_state);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
new file mode 100644 (file)
index 0000000..7e70c71
--- /dev/null
@@ -0,0 +1,2527 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "../rtl8723com/dm_common.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
+#include "led.h"
+#include "hw.h"
+#include "pwrseq.h"
+#include "../btcoexist/rtl_btc.h"
+
+#define LLT_CONFIG     5
+
+static void _rtl8723be_return_beacon_queue_skb(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+       while (skb_queue_len(&ring->queue)) {
+               struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+               struct sk_buff *skb = __skb_dequeue(&ring->queue);
+
+               pci_unmap_single(rtlpci->pdev,
+                                rtlpriv->cfg->ops->get_desc(
+                                (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
+                                skb->len, PCI_DMA_TODEVICE);
+               kfree_skb(skb);
+               ring->idx = (ring->idx + 1) % ring->entries;
+       }
+}
+
+static void _rtl8723be_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
+                                       u8 set_bits, u8 clear_bits)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpci->reg_bcn_ctrl_val |= set_bits;
+       rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
+
+       rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+}
+
+static void _rtl8723be_stop_tx_beacon(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmp1byte;
+
+       tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+       rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6)));
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64);
+       tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+       tmp1byte &= ~(BIT(0));
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl8723be_resume_tx_beacon(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmp1byte;
+
+       tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+       rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6));
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+       tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+       tmp1byte |= BIT(1);
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl8723be_enable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+       _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(1));
+}
+
+static void _rtl8723be_disable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+       _rtl8723be_set_bcn_ctrl_reg(hw, BIT(1), 0);
+}
+
+static void _rtl8723be_set_fw_clock_on(struct ieee80211_hw *hw, u8 rpwm_val,
+                                      bool need_turn_off_ckk)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       bool support_remote_wake_up;
+       u32 count = 0, isr_regaddr, content;
+       bool schedule_timer = need_turn_off_ckk;
+       rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+                                     (u8 *)(&support_remote_wake_up));
+
+       if (!rtlhal->fw_ready)
+               return;
+       if (!rtlpriv->psc.fw_current_inpsmode)
+               return;
+
+       while (1) {
+               spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+               if (rtlhal->fw_clk_change_in_progress) {
+                       while (rtlhal->fw_clk_change_in_progress) {
+                               spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+                               count++;
+                               udelay(100);
+                               if (count > 1000)
+                                       return;
+                               spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+                       }
+                       spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+               } else {
+                       rtlhal->fw_clk_change_in_progress = false;
+                       spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+                       break;
+               }
+       }
+       if (IS_IN_LOW_POWER_STATE_88E(rtlhal->fw_ps_state)) {
+               rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
+                                             (u8 *)(&rpwm_val));
+               if (FW_PS_IS_ACK(rpwm_val)) {
+                       isr_regaddr = REG_HISR;
+                       content = rtl_read_dword(rtlpriv, isr_regaddr);
+                       while (!(content & IMR_CPWM) && (count < 500)) {
+                               udelay(50);
+                               count++;
+                               content = rtl_read_dword(rtlpriv, isr_regaddr);
+                       }
+
+                       if (content & IMR_CPWM) {
+                               rtl_write_word(rtlpriv, isr_regaddr, 0x0100);
+                               rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_88E;
+                               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                                        "Receive CPWM INT!!! Set "
+                                        "pHalData->FwPSState = %X\n",
+                                        rtlhal->fw_ps_state);
+                       }
+               }
+               spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+               rtlhal->fw_clk_change_in_progress = false;
+               spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+               if (schedule_timer) {
+                       mod_timer(&rtlpriv->works.fw_clockoff_timer,
+                                 jiffies + MSECS(10));
+               }
+       } else  {
+               spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+               rtlhal->fw_clk_change_in_progress = false;
+               spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+       }
+}
+
+static void _rtl8723be_set_fw_clock_off(struct ieee80211_hw *hw, u8 rpwm_val)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl8192_tx_ring *ring;
+       enum rf_pwrstate rtstate;
+       bool schedule_timer = false;
+       u8 queue;
+
+       if (!rtlhal->fw_ready)
+               return;
+       if (!rtlpriv->psc.fw_current_inpsmode)
+               return;
+       if (!rtlhal->allow_sw_to_change_hwclc)
+               return;
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, (u8 *)(&rtstate));
+       if (rtstate == ERFOFF || rtlpriv->psc.inactive_pwrstate == ERFOFF)
+               return;
+
+       for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) {
+               ring = &rtlpci->tx_ring[queue];
+               if (skb_queue_len(&ring->queue)) {
+                       schedule_timer = true;
+                       break;
+               }
+       }
+       if (schedule_timer) {
+               mod_timer(&rtlpriv->works.fw_clockoff_timer,
+                         jiffies + MSECS(10));
+               return;
+       }
+       if (FW_PS_STATE(rtlhal->fw_ps_state) !=
+           FW_PS_STATE_RF_OFF_LOW_PWR_88E) {
+               spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+               if (!rtlhal->fw_clk_change_in_progress) {
+                       rtlhal->fw_clk_change_in_progress = true;
+                       spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+                       rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
+                       rtl_write_word(rtlpriv, REG_HISR, 0x0100);
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+                                                     (u8 *)(&rpwm_val));
+                       spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+                       rtlhal->fw_clk_change_in_progress = false;
+                       spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+               } else {
+                       spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+                       mod_timer(&rtlpriv->works.fw_clockoff_timer,
+                                 jiffies + MSECS(10));
+               }
+       }
+}
+
+static void _rtl8723be_set_fw_ps_rf_on(struct ieee80211_hw *hw)
+{
+       u8 rpwm_val = 0;
+       rpwm_val |= (FW_PS_STATE_RF_OFF_88E | FW_PS_ACK);
+       _rtl8723be_set_fw_clock_on(hw, rpwm_val, true);
+}
+
+static void _rtl8723be_fwlps_leave(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       bool fw_current_inps = false;
+       u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE;
+
+       if (ppsc->low_power_enable) {
+               rpwm_val = (FW_PS_STATE_ALL_ON_88E | FW_PS_ACK);/* RF on */
+               _rtl8723be_set_fw_clock_on(hw, rpwm_val, false);
+               rtlhal->allow_sw_to_change_hwclc = false;
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+                                             (u8 *)(&fw_pwrmode));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+                                             (u8 *)(&fw_current_inps));
+       } else {
+               rpwm_val = FW_PS_STATE_ALL_ON_88E;      /* RF on */
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+                                             (u8 *)(&rpwm_val));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+                                             (u8 *)(&fw_pwrmode));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+                                             (u8 *)(&fw_current_inps));
+       }
+}
+
+static void _rtl8723be_fwlps_enter(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       bool fw_current_inps = true;
+       u8 rpwm_val;
+
+       if (ppsc->low_power_enable) {
+               rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR_88E;      /* RF off */
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+                                             (u8 *)(&fw_current_inps));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+                                             (u8 *)(&ppsc->fwctrl_psmode));
+               rtlhal->allow_sw_to_change_hwclc = true;
+               _rtl8723be_set_fw_clock_off(hw, rpwm_val);
+
+       } else {
+               rpwm_val = FW_PS_STATE_RF_OFF_88E;      /* RF off */
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+                                             (u8 *)(&fw_current_inps));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+                                             (u8 *)(&ppsc->fwctrl_psmode));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+                                             (u8 *)(&rpwm_val));
+       }
+}
+
+void rtl8723be_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       switch (variable) {
+       case HW_VAR_RCR:
+               *((u32 *)(val)) = rtlpci->receive_config;
+               break;
+       case HW_VAR_RF_STATE:
+               *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+               break;
+       case HW_VAR_FWLPS_RF_ON: {
+               enum rf_pwrstate rfstate;
+               u32 val_rcr;
+
+               rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE,
+                                             (u8 *)(&rfstate));
+               if (rfstate == ERFOFF) {
+                       *((bool *)(val)) = true;
+               } else {
+                       val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+                       val_rcr &= 0x00070000;
+                       if (val_rcr)
+                               *((bool *)(val)) = false;
+                       else
+                               *((bool *)(val)) = true;
+               }
+               break; }
+       case HW_VAR_FW_PSMODE_STATUS:
+               *((bool *)(val)) = ppsc->fw_current_inpsmode;
+               break;
+       case HW_VAR_CORRECT_TSF: {
+               u64 tsf;
+               u32 *ptsf_low = (u32 *)&tsf;
+               u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+               *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
+               *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+               *((u64 *)(val)) = tsf;
+
+               break; }
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process %x\n", variable);
+               break;
+       }
+}
+
+void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       u8 idx;
+
+       switch (variable) {
+       case HW_VAR_ETHER_ADDR:
+               for (idx = 0; idx < ETH_ALEN; idx++)
+                       rtl_write_byte(rtlpriv, (REG_MACID + idx), val[idx]);
+               break;
+       case HW_VAR_BASIC_RATE: {
+               u16 rate_cfg = ((u16 *)val)[0];
+               u8 rate_index = 0;
+               rate_cfg = rate_cfg & 0x15f;
+               rate_cfg |= 0x01;
+               rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
+               rtl_write_byte(rtlpriv, REG_RRSR + 1, (rate_cfg >> 8) & 0xff);
+               while (rate_cfg > 0x1) {
+                       rate_cfg = (rate_cfg >> 1);
+                       rate_index++;
+               }
+               rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, rate_index);
+               break; }
+       case HW_VAR_BSSID:
+               for (idx = 0; idx < ETH_ALEN; idx++)
+                       rtl_write_byte(rtlpriv, (REG_BSSID + idx), val[idx]);
+               break;
+       case HW_VAR_SIFS:
+               rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
+               rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]);
+
+               rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
+               rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+
+               if (!mac->ht_enable)
+                       rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, 0x0e0e);
+               else
+                       rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+                                      *((u16 *)val));
+               break;
+       case HW_VAR_SLOT_TIME: {
+               u8 e_aci;
+
+               RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+                        "HW_VAR_SLOT_TIME %x\n", val[0]);
+
+               rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
+
+               for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+                                                     (u8 *)(&e_aci));
+               }
+               break; }
+       case HW_VAR_ACK_PREAMBLE: {
+               u8 reg_tmp;
+               u8 short_preamble = (bool) (*(u8 *)val);
+               reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL + 2);
+               if (short_preamble) {
+                       reg_tmp |= 0x02;
+                       rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+               } else {
+                       reg_tmp &= 0xFD;
+                       rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+               }
+               break; }
+       case HW_VAR_WPA_CONFIG:
+               rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
+               break;
+       case HW_VAR_AMPDU_MIN_SPACE: {
+               u8 min_spacing_to_set;
+               u8 sec_min_space;
+
+               min_spacing_to_set = *((u8 *)val);
+               if (min_spacing_to_set <= 7) {
+                       sec_min_space = 0;
+
+                       if (min_spacing_to_set < sec_min_space)
+                               min_spacing_to_set = sec_min_space;
+
+                       mac->min_space_cfg = ((mac->min_space_cfg & 0xf8) |
+                                             min_spacing_to_set);
+
+                       *val = min_spacing_to_set;
+
+                       RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+                                "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+                                mac->min_space_cfg);
+
+                       rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+                                      mac->min_space_cfg);
+               }
+               break; }
+       case HW_VAR_SHORTGI_DENSITY: {
+               u8 density_to_set;
+
+               density_to_set = *((u8 *)val);
+               mac->min_space_cfg |= (density_to_set << 3);
+
+               RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+                        "Set HW_VAR_SHORTGI_DENSITY: %#x\n",
+                        mac->min_space_cfg);
+
+               rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+                              mac->min_space_cfg);
+               break; }
+       case HW_VAR_AMPDU_FACTOR: {
+               u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9};
+               u8 factor_toset;
+               u8 *p_regtoset = NULL;
+               u8 index = 0;
+
+               p_regtoset = regtoset_normal;
+
+               factor_toset = *((u8 *)val);
+               if (factor_toset <= 3) {
+                       factor_toset = (1 << (factor_toset + 2));
+                       if (factor_toset > 0xf)
+                               factor_toset = 0xf;
+
+                       for (index = 0; index < 4; index++) {
+                               if ((p_regtoset[index] & 0xf0) >
+                                   (factor_toset << 4))
+                                       p_regtoset[index] =
+                                               (p_regtoset[index] & 0x0f) |
+                                               (factor_toset << 4);
+
+                               if ((p_regtoset[index] & 0x0f) > factor_toset)
+                                       p_regtoset[index] =
+                                               (p_regtoset[index] & 0xf0) |
+                                               (factor_toset);
+
+                               rtl_write_byte(rtlpriv,
+                                              (REG_AGGLEN_LMT + index),
+                                              p_regtoset[index]);
+                       }
+                       RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+                                "Set HW_VAR_AMPDU_FACTOR: %#x\n",
+                                factor_toset);
+               }
+               break; }
+       case HW_VAR_AC_PARAM: {
+               u8 e_aci = *((u8 *)val);
+               rtl8723_dm_init_edca_turbo(hw);
+
+               if (rtlpci->acm_method != EACMWAY2_SW)
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
+                                                     (u8 *)(&e_aci));
+               break; }
+       case HW_VAR_ACM_CTRL: {
+               u8 e_aci = *((u8 *)val);
+               union aci_aifsn *p_aci_aifsn =
+                               (union aci_aifsn *)(&(mac->ac[0].aifs));
+               u8 acm = p_aci_aifsn->f.acm;
+               u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
+
+               acm_ctrl =
+                   acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+
+               if (acm) {
+                       switch (e_aci) {
+                       case AC0_BE:
+                               acm_ctrl |= ACMHW_BEQEN;
+                               break;
+                       case AC2_VI:
+                               acm_ctrl |= ACMHW_VIQEN;
+                               break;
+                       case AC3_VO:
+                               acm_ctrl |= ACMHW_VOQEN;
+                               break;
+                       default:
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                        "HW_VAR_ACM_CTRL acm set "
+                                         "failed: eACI is %d\n", acm);
+                               break;
+                       }
+               } else {
+                       switch (e_aci) {
+                       case AC0_BE:
+                               acm_ctrl &= (~ACMHW_BEQEN);
+                               break;
+                       case AC2_VI:
+                               acm_ctrl &= (~ACMHW_VIQEN);
+                               break;
+                       case AC3_VO:
+                               acm_ctrl &= (~ACMHW_BEQEN);
+                               break;
+                       default:
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                        "switch case not process\n");
+                               break;
+                       }
+               }
+               RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+                        "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] "
+                        "Write 0x%X\n", acm_ctrl);
+               rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
+               break; }
+       case HW_VAR_RCR:
+               rtl_write_dword(rtlpriv, REG_RCR, ((u32 *)(val))[0]);
+               rtlpci->receive_config = ((u32 *)(val))[0];
+               break;
+       case HW_VAR_RETRY_LIMIT: {
+               u8 retry_limit = ((u8 *)(val))[0];
+
+               rtl_write_word(rtlpriv, REG_RL,
+                              retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+                              retry_limit << RETRY_LIMIT_LONG_SHIFT);
+               break; }
+       case HW_VAR_DUAL_TSF_RST:
+               rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
+               break;
+       case HW_VAR_EFUSE_BYTES:
+               rtlefuse->efuse_usedbytes = *((u16 *)val);
+               break;
+       case HW_VAR_EFUSE_USAGE:
+               rtlefuse->efuse_usedpercentage = *((u8 *)val);
+               break;
+       case HW_VAR_IO_CMD:
+               rtl8723be_phy_set_io_cmd(hw, (*(enum io_type *)val));
+               break;
+       case HW_VAR_SET_RPWM: {
+               u8 rpwm_val;
+
+               rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
+               udelay(1);
+
+               if (rpwm_val & BIT(7)) {
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, (*(u8 *)val));
+               } else {
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+                                      ((*(u8 *)val) | BIT(7)));
+               }
+               break; }
+       case HW_VAR_H2C_FW_PWRMODE:
+               rtl8723be_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
+               break;
+       case HW_VAR_FW_PSMODE_STATUS:
+               ppsc->fw_current_inpsmode = *((bool *)val);
+               break;
+       case HW_VAR_RESUME_CLK_ON:
+               _rtl8723be_set_fw_ps_rf_on(hw);
+               break;
+       case HW_VAR_FW_LPS_ACTION: {
+               bool enter_fwlps = *((bool *)val);
+
+               if (enter_fwlps)
+                       _rtl8723be_fwlps_enter(hw);
+               else
+                       _rtl8723be_fwlps_leave(hw);
+
+               break; }
+       case HW_VAR_H2C_FW_JOINBSSRPT: {
+               u8 mstatus = (*(u8 *)val);
+               u8 tmp_regcr, tmp_reg422, bcnvalid_reg;
+               u8 count = 0, dlbcn_count = 0;
+               bool recover = false;
+
+               if (mstatus == RT_MEDIA_CONNECT) {
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
+
+                       tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+                       rtl_write_byte(rtlpriv, REG_CR + 1,
+                                      (tmp_regcr | BIT(0)));
+
+                       _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(3));
+                       _rtl8723be_set_bcn_ctrl_reg(hw, BIT(4), 0);
+
+                       tmp_reg422 = rtl_read_byte(rtlpriv,
+                                                  REG_FWHW_TXQ_CTRL + 2);
+                       rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+                                      tmp_reg422 & (~BIT(6)));
+                       if (tmp_reg422 & BIT(6))
+                               recover = true;
+
+                       do {
+                               bcnvalid_reg = rtl_read_byte(rtlpriv,
+                                                            REG_TDECTRL + 2);
+                               rtl_write_byte(rtlpriv, REG_TDECTRL + 2,
+                                              (bcnvalid_reg | BIT(0)));
+                               _rtl8723be_return_beacon_queue_skb(hw);
+
+                               rtl8723be_set_fw_rsvdpagepkt(hw, 0);
+                               bcnvalid_reg = rtl_read_byte(rtlpriv,
+                                                            REG_TDECTRL + 2);
+                               count = 0;
+                               while (!(bcnvalid_reg & BIT(0)) && count < 20) {
+                                       count++;
+                                       udelay(10);
+                                       bcnvalid_reg = rtl_read_byte(rtlpriv,
+                                                              REG_TDECTRL + 2);
+                               }
+                               dlbcn_count++;
+                       } while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5);
+
+                       if (bcnvalid_reg & BIT(0))
+                               rtl_write_byte(rtlpriv, REG_TDECTRL+2, BIT(0));
+
+                       _rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0);
+                       _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+                       if (recover) {
+                               rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+                                              tmp_reg422);
+                       }
+                       rtl_write_byte(rtlpriv, REG_CR + 1,
+                                      (tmp_regcr & ~(BIT(0))));
+               }
+               rtl8723be_set_fw_joinbss_report_cmd(hw, (*(u8 *)val));
+               break; }
+       case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+               rtl8723be_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+               break;
+       case HW_VAR_AID: {
+               u16 u2btmp;
+               u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
+               u2btmp &= 0xC000;
+               rtl_write_word(rtlpriv, REG_BCN_PSR_RPT,
+                              (u2btmp | mac->assoc_id));
+               break; }
+       case HW_VAR_CORRECT_TSF: {
+               u8 btype_ibss = ((u8 *)(val))[0];
+
+               if (btype_ibss)
+                       _rtl8723be_stop_tx_beacon(hw);
+
+               _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(3));
+
+               rtl_write_dword(rtlpriv, REG_TSFTR,
+                               (u32) (mac->tsf & 0xffffffff));
+               rtl_write_dword(rtlpriv, REG_TSFTR + 4,
+                               (u32) ((mac->tsf >> 32) & 0xffffffff));
+
+               _rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0);
+
+               if (btype_ibss)
+                       _rtl8723be_resume_tx_beacon(hw);
+               break; }
+       case HW_VAR_KEEP_ALIVE: {
+               u8 array[2];
+               array[0] = 0xff;
+               array[1] = *((u8 *)val);
+               rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_KEEP_ALIVE_CTRL,
+                                      2, array);
+               break; }
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process %x\n",
+                        variable);
+               break;
+       }
+}
+
+static bool _rtl8723be_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       bool status = true;
+       int count = 0;
+       u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) |
+                   _LLT_OP(_LLT_WRITE_ACCESS);
+
+       rtl_write_dword(rtlpriv, REG_LLT_INIT, value);
+
+       do {
+               value = rtl_read_dword(rtlpriv, REG_LLT_INIT);
+               if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
+                       break;
+
+               if (count > POLLING_LLT_THRESHOLD) {
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "Failed to polling write LLT done at "
+                                 "address %d!\n", address);
+                       status = false;
+                       break;
+               }
+       } while (++count);
+
+       return status;
+}
+
+static bool _rtl8723be_llt_table_init(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       unsigned short i;
+       u8 txpktbuf_bndy;
+       u8 maxpage;
+       bool status;
+
+       maxpage = 255;
+       txpktbuf_bndy = 245;
+
+       rtl_write_dword(rtlpriv, REG_TRXFF_BNDY,
+                       (0x27FF0000 | txpktbuf_bndy));
+       rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy);
+
+       rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+       rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+
+       rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy);
+       rtl_write_byte(rtlpriv, REG_PBP, 0x31);
+       rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4);
+
+       for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+               status = _rtl8723be_llt_write(hw, i, i + 1);
+               if (!status)
+                       return status;
+       }
+       status = _rtl8723be_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
+
+       if (!status)
+               return status;
+
+       for (i = txpktbuf_bndy; i < maxpage; i++) {
+               status = _rtl8723be_llt_write(hw, i, (i + 1));
+               if (!status)
+                       return status;
+       }
+       status = _rtl8723be_llt_write(hw, maxpage, txpktbuf_bndy);
+       if (!status)
+               return status;
+
+       rtl_write_dword(rtlpriv, REG_RQPN, 0x80e40808);
+       rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x00);
+
+       return true;
+}
+
+static void _rtl8723be_gen_refresh_led_state(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_led *pled0 = &(pcipriv->ledctl.sw_led0);
+
+       if (rtlpriv->rtlhal.up_first_time)
+               return;
+
+       if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+               rtl8723be_sw_led_on(hw, pled0);
+       else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT)
+               rtl8723be_sw_led_on(hw, pled0);
+       else
+               rtl8723be_sw_led_off(hw, pled0);
+}
+
+static bool _rtl8723be_init_mac(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       unsigned char bytetmp;
+       unsigned short wordtmp;
+       u16 retry = 0;
+       bool mac_func_enable;
+
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
+
+       /*Auto Power Down to CHIP-off State*/
+       bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) & (~BIT(7));
+       rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp);
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_CR);
+       if (bytetmp == 0xFF)
+               mac_func_enable = true;
+       else
+               mac_func_enable = false;
+
+       /* HW Power on sequence */
+       if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
+                                     PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
+                                     RTL8723_NIC_ENABLE_FLOW)) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "init MAC Fail as power on failure\n");
+               return false;
+       }
+       bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO) | BIT(4);
+       rtl_write_byte(rtlpriv, REG_APS_FSMCO, bytetmp);
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_CR);
+       bytetmp = 0xff;
+       rtl_write_byte(rtlpriv, REG_CR, bytetmp);
+       mdelay(2);
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_HWSEQ_CTRL);
+       bytetmp |= 0x7f;
+       rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, bytetmp);
+       mdelay(2);
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CFG + 3);
+       if (bytetmp & BIT(0)) {
+               bytetmp = rtl_read_byte(rtlpriv, 0x7c);
+               bytetmp |= BIT(6);
+               rtl_write_byte(rtlpriv, 0x7c, bytetmp);
+       }
+       bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR);
+       bytetmp |= BIT(3);
+       rtl_write_byte(rtlpriv, REG_SYS_CLKR, bytetmp);
+       bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG + 1);
+       bytetmp &= ~BIT(4);
+       rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG + 1, bytetmp);
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG+3);
+       rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+3, bytetmp | 0x77);
+
+       rtl_write_word(rtlpriv, REG_CR, 0x2ff);
+
+       if (!mac_func_enable) {
+               if (!_rtl8723be_llt_table_init(hw))
+                       return false;
+       }
+       rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
+       rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff);
+
+       /* Enable FW Beamformer Interrupt */
+       bytetmp = rtl_read_byte(rtlpriv, REG_FWIMR + 3);
+       rtl_write_byte(rtlpriv, REG_FWIMR + 3, bytetmp | BIT(6));
+
+       wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL);
+       wordtmp &= 0xf;
+       wordtmp |= 0xF5B1;
+       rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp);
+
+       rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F);
+       rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+       rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xFFFF);
+       rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config);
+
+       rtl_write_byte(rtlpriv, 0x4d0, 0x0);
+
+       rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
+                       ((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) &
+                       DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_MGQ_DESA,
+                       (u64) rtlpci->tx_ring[MGNT_QUEUE].dma &
+                       DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_VOQ_DESA,
+                       (u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_VIQ_DESA,
+                       (u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_BEQ_DESA,
+                       (u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_BKQ_DESA,
+                       (u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_HQ_DESA,
+                       (u64) rtlpci->tx_ring[HIGH_QUEUE].dma &
+                       DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_RX_DESA,
+                       (u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma &
+                       DMA_BIT_MASK(32));
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 3);
+       rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, bytetmp | 0x77);
+
+       rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
+       rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6));
+
+       rtl_write_byte(rtlpriv, REG_SECONDARY_CCA_CTRL, 0x3);
+
+       do {
+               retry++;
+               bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
+       } while ((retry < 200) && (bytetmp & BIT(7)));
+
+       _rtl8723be_gen_refresh_led_state(hw);
+
+       rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+       rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, bytetmp & ~BIT(2));
+
+       return true;
+}
+
+static void _rtl8723be_hw_configure(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 reg_bw_opmode;
+       u32 reg_ratr, reg_prsr;
+
+       reg_bw_opmode = BW_OPMODE_20MHZ;
+       reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
+                  RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
+       reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+
+       rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr);
+       rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF);
+}
+
+static void _rtl8723be_enable_aspm_back_door(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       rtl_write_byte(rtlpriv, 0x34b, 0x93);
+       rtl_write_word(rtlpriv, 0x350, 0x870c);
+       rtl_write_byte(rtlpriv, 0x352, 0x1);
+
+       if (ppsc->support_backdoor)
+               rtl_write_byte(rtlpriv, 0x349, 0x1b);
+       else
+               rtl_write_byte(rtlpriv, 0x349, 0x03);
+
+       rtl_write_word(rtlpriv, 0x350, 0x2718);
+       rtl_write_byte(rtlpriv, 0x352, 0x1);
+}
+
+void rtl8723be_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 sec_reg_value;
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
+                rtlpriv->sec.pairwise_enc_algorithm,
+                rtlpriv->sec.group_enc_algorithm);
+
+       if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+               RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                        "not open hw encryption\n");
+               return;
+       }
+       sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE;
+
+       if (rtlpriv->sec.use_defaultkey) {
+               sec_reg_value |= SCR_TXUSEDK;
+               sec_reg_value |= SCR_RXUSEDK;
+       }
+       sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
+
+       rtl_write_byte(rtlpriv, REG_CR + 1, 0x02);
+
+       RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "The SECR-value %x\n",
+                sec_reg_value);
+
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+}
+
+int rtl8723be_hw_init(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       bool rtstatus = true;
+       int err;
+       u8 tmp_u1b;
+       unsigned long flags;
+
+       /* reenable interrupts to not interfere with other devices */
+       local_save_flags(flags);
+       local_irq_enable();
+
+       rtlpriv->rtlhal.being_init_adapter = true;
+       rtlpriv->intf_ops->disable_aspm(hw);
+       rtstatus = _rtl8723be_init_mac(hw);
+       if (!rtstatus) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
+               err = 1;
+               goto exit;
+       }
+       tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CFG);
+       tmp_u1b &= 0x7F;
+       rtl_write_byte(rtlpriv, REG_SYS_CFG, tmp_u1b);
+
+       err = rtl8723_download_fw(hw, true);
+       if (err) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "Failed to download FW. Init HW without FW now..\n");
+               err = 1;
+               rtlhal->fw_ready = false;
+               goto exit;
+       } else {
+               rtlhal->fw_ready = true;
+       }
+       rtlhal->last_hmeboxnum = 0;
+       rtl8723be_phy_mac_config(hw);
+       /* because last function modify RCR, so we update
+        * rcr var here, or TP will unstable for receive_config
+        * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx
+        * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
+        */
+       rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR);
+       rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
+       rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+       rtl8723be_phy_bb_config(hw);
+       rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
+       rtl8723be_phy_rf_config(hw);
+
+       rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
+                                                RF_CHNLBW, RFREG_OFFSET_MASK);
+       rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1,
+                                                RF_CHNLBW, RFREG_OFFSET_MASK);
+       rtlphy->rfreg_chnlval[0] &= 0xFFF03FF;
+       rtlphy->rfreg_chnlval[0] |= (BIT(10) | BIT(11));
+
+       rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
+       rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
+       rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
+       _rtl8723be_hw_configure(hw);
+       rtl_cam_reset_all_entry(hw);
+       rtl8723be_enable_hw_security_config(hw);
+
+       ppsc->rfpwr_state = ERFON;
+
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+       _rtl8723be_enable_aspm_back_door(hw);
+       rtlpriv->intf_ops->enable_aspm(hw);
+
+       rtl8723be_bt_hw_init(hw);
+
+       rtl_set_bbreg(hw, 0x64, BIT(20), 0);
+       rtl_set_bbreg(hw, 0x64, BIT(24), 0);
+
+       rtl_set_bbreg(hw, 0x40, BIT(4), 0);
+       rtl_set_bbreg(hw, 0x40, BIT(3), 1);
+
+       rtl_set_bbreg(hw, 0x944, BIT(0)|BIT(1), 0x3);
+       rtl_set_bbreg(hw, 0x930, 0xff, 0x77);
+
+       rtl_set_bbreg(hw, 0x38, BIT(11), 0x1);
+
+       rtl_set_bbreg(hw, 0xb2c, 0xffffffff, 0x80000000);
+
+       if (ppsc->rfpwr_state == ERFON) {
+               rtl8723be_dm_check_txpower_tracking(hw);
+               rtl8723be_phy_lc_calibrate(hw);
+       }
+       tmp_u1b = efuse_read_1byte(hw, 0x1FA);
+       if (!(tmp_u1b & BIT(0))) {
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05);
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "PA BIAS path A\n");
+       }
+       if (!(tmp_u1b & BIT(4))) {
+               tmp_u1b = rtl_read_byte(rtlpriv, 0x16);
+               tmp_u1b &= 0x0F;
+               rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80);
+               udelay(10);
+               rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90);
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
+       }
+       rtl8723be_dm_init(hw);
+exit:
+       local_irq_restore(flags);
+       rtlpriv->rtlhal.being_init_adapter = false;
+       return err;
+}
+
+static enum version_8723e _rtl8723be_read_chip_version(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       enum version_8723e version = VERSION_UNKNOWN;
+       u8 count = 0;
+       u8 value8;
+       u32 value32;
+
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0);
+
+       value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 2);
+       rtl_write_byte(rtlpriv, REG_APS_FSMCO + 2, value8 | BIT(0));
+
+       value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
+       rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, value8 | BIT(0));
+
+       value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
+       while (((value8 & BIT(0))) && (count++ < 100)) {
+               udelay(10);
+               value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
+       }
+       count = 0;
+       value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION);
+       while ((value8 == 0) && (count++ < 50)) {
+               value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION);
+               mdelay(1);
+       }
+       value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG1);
+       if ((value32 & (CHIP_8723B)) != CHIP_8723B)
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "unkown chip version\n");
+       else
+               version = (enum version_8723e) VERSION_TEST_CHIP_1T1R_8723B;
+
+               rtlphy->rf_type = RF_1T1R;
+
+       value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION);
+       if (value8 >= 0x02)
+               version |= BIT(3);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ?
+                "RF_2T2R" : "RF_1T1R");
+
+       return version;
+}
+
+static int _rtl8723be_set_media_status(struct ieee80211_hw *hw,
+                                      enum nl80211_iftype type)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 bt_msr = rtl_read_byte(rtlpriv, MSR) & 0xfc;
+       enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+
+       rtl_write_dword(rtlpriv, REG_BCN_CTRL, 0);
+       RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD,
+                "clear 0x550 when set HW_VAR_MEDIA_STATUS\n");
+
+       if (type == NL80211_IFTYPE_UNSPECIFIED ||
+           type == NL80211_IFTYPE_STATION) {
+               _rtl8723be_stop_tx_beacon(hw);
+               _rtl8723be_enable_bcn_sub_func(hw);
+       } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) {
+               _rtl8723be_resume_tx_beacon(hw);
+               _rtl8723be_disable_bcn_sub_func(hw);
+       } else {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "Set HW_VAR_MEDIA_STATUS: "
+                        "No such media status(%x).\n", type);
+       }
+       switch (type) {
+       case NL80211_IFTYPE_UNSPECIFIED:
+               bt_msr |= MSR_NOLINK;
+               ledaction = LED_CTL_LINK;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Set Network type to NO LINK!\n");
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               bt_msr |= MSR_ADHOC;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Set Network type to Ad Hoc!\n");
+               break;
+       case NL80211_IFTYPE_STATION:
+               bt_msr |= MSR_INFRA;
+               ledaction = LED_CTL_LINK;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Set Network type to STA!\n");
+               break;
+       case NL80211_IFTYPE_AP:
+               bt_msr |= MSR_AP;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Set Network type to AP!\n");
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Network type %d not support!\n", type);
+               return 1;
+       }
+       rtl_write_byte(rtlpriv, (MSR), bt_msr);
+       rtlpriv->cfg->ops->led_control(hw, ledaction);
+       if ((bt_msr & 0x03) == MSR_AP)
+               rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
+       else
+               rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
+       return 0;
+}
+
+void rtl8723be_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       u32 reg_rcr = rtlpci->receive_config;
+
+       if (rtlpriv->psc.rfpwr_state != ERFON)
+               return;
+
+       if (check_bssid) {
+               reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+                                             (u8 *)(&reg_rcr));
+               _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(4));
+       } else if (!check_bssid) {
+               reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
+               _rtl8723be_set_bcn_ctrl_reg(hw, BIT(4), 0);
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+                                             (u8 *)(&reg_rcr));
+       }
+}
+
+int rtl8723be_set_network_type(struct ieee80211_hw *hw,
+                              enum nl80211_iftype type)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (_rtl8723be_set_media_status(hw, type))
+               return -EOPNOTSUPP;
+
+       if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+               if (type != NL80211_IFTYPE_AP)
+                       rtl8723be_set_check_bssid(hw, true);
+       } else {
+               rtl8723be_set_check_bssid(hw, false);
+       }
+       return 0;
+}
+
+/* don't set REG_EDCA_BE_PARAM here
+ * because mac80211 will send pkt when scan
+ */
+void rtl8723be_set_qos(struct ieee80211_hw *hw, int aci)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       rtl8723_dm_init_edca_turbo(hw);
+       switch (aci) {
+       case AC1_BK:
+               rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
+               break;
+       case AC0_BE:
+               break;
+       case AC2_VI:
+               rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
+               break;
+       case AC3_VO:
+               rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
+               break;
+       default:
+               RT_ASSERT(false, "invalid aci: %d !\n", aci);
+               break;
+       }
+}
+
+void rtl8723be_enable_interrupt(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
+       rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+       rtlpci->irq_enabled = true;
+       /* there are some C2H CMDs have been sent
+        * before system interrupt is enabled, e.g., C2H, CPWM.
+        * So we need to clear all C2H events that FW has notified,
+        * otherwise FW won't schedule any commands anymore.
+        */
+       rtl_write_byte(rtlpriv, REG_C2HEVT_CLEAR, 0);
+       /*enable system interrupt*/
+       rtl_write_dword(rtlpriv, REG_HSIMR, rtlpci->sys_irq_mask & 0xFFFFFFFF);
+}
+
+void rtl8723be_disable_interrupt(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED);
+       rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED);
+       rtlpci->irq_enabled = false;
+       synchronize_irq(rtlpci->pdev->irq);
+}
+
+static void _rtl8723be_poweroff_adapter(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 u1b_tmp;
+
+       /* Combo (PCIe + USB) Card and PCIe-MF Card */
+       /* 1. Run LPS WL RFOFF flow */
+       rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+                                PWR_INTF_PCI_MSK, RTL8723_NIC_LPS_ENTER_FLOW);
+
+       /* 2. 0x1F[7:0] = 0 */
+       /* turn off RF */
+       rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
+       if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) &&
+           rtlhal->fw_ready)
+               rtl8723be_firmware_selfreset(hw);
+
+       /* Reset MCU. Suggested by Filen. */
+       u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+
+       /* g.   MCUFWDL 0x80[1:0]= 0     */
+       /* reset MCU ready status */
+       rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+
+       /* HW card disable configuration. */
+       rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+                                PWR_INTF_PCI_MSK, RTL8723_NIC_DISABLE_FLOW);
+
+       /* Reset MCU IO Wrapper */
+       u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
+       u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1b_tmp | BIT(0));
+
+       /* 7. RSV_CTRL 0x1C[7:0] = 0x0E */
+       /* lock ISO/CLK/Power control register */
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
+}
+
+void rtl8723be_card_disable(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       enum nl80211_iftype opmode;
+
+       mac->link_state = MAC80211_NOLINK;
+       opmode = NL80211_IFTYPE_UNSPECIFIED;
+       _rtl8723be_set_media_status(hw, opmode);
+       if (rtlpriv->rtlhal.driver_is_goingto_unload ||
+           ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+               rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+       RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+       _rtl8723be_poweroff_adapter(hw);
+
+       /* after power off we should do iqk again */
+       rtlpriv->phy.iqk_initialized = false;
+}
+
+void rtl8723be_interrupt_recognized(struct ieee80211_hw *hw,
+                                   u32 *p_inta, u32 *p_intb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0];
+       rtl_write_dword(rtlpriv, ISR, *p_inta);
+
+       *p_intb = rtl_read_dword(rtlpriv, REG_HISRE) &
+                                       rtlpci->irq_mask[1];
+       rtl_write_dword(rtlpriv, REG_HISRE, *p_intb);
+}
+
+void rtl8723be_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u16 bcn_interval, atim_window;
+
+       bcn_interval = mac->beacon_interval;
+       atim_window = 2;        /*FIX MERGE */
+       rtl8723be_disable_interrupt(hw);
+       rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
+       rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+       rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
+       rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18);
+       rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18);
+       rtl_write_byte(rtlpriv, 0x606, 0x30);
+       rtl8723be_enable_interrupt(hw);
+}
+
+void rtl8723be_set_beacon_interval(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u16 bcn_interval = mac->beacon_interval;
+
+       RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
+                "beacon_interval:%d\n", bcn_interval);
+       rtl8723be_disable_interrupt(hw);
+       rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+       rtl8723be_enable_interrupt(hw);
+}
+
+void rtl8723be_update_interrupt_mask(struct ieee80211_hw *hw,
+                                  u32 add_msr, u32 rm_msr)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+                "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr);
+
+       if (add_msr)
+               rtlpci->irq_mask[0] |= add_msr;
+       if (rm_msr)
+               rtlpci->irq_mask[0] &= (~rm_msr);
+       rtl8723be_disable_interrupt(hw);
+       rtl8723be_enable_interrupt(hw);
+}
+
+static u8 _rtl8723be_get_chnl_group(u8 chnl)
+{
+       u8 group;
+
+       if (chnl < 3)
+               group = 0;
+       else if (chnl < 9)
+               group = 1;
+       else
+               group = 2;
+       return group;
+}
+
+static void _rtl8723be_read_power_value_fromprom(struct ieee80211_hw *hw,
+                                       struct txpower_info_2g *pw2g,
+                                       struct txpower_info_5g *pw5g,
+                                       bool autoload_fail, u8 *hwinfo)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 path, addr = EEPROM_TX_PWR_INX, group, cnt = 0;
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "hal_ReadPowerValueFromPROM8723BE(): "
+                "PROMContent[0x%x]= 0x%x\n",
+                (addr + 1), hwinfo[addr + 1]);
+       if (0xFF == hwinfo[addr + 1])  /*YJ, add, 120316*/
+               autoload_fail = true;
+
+       if (autoload_fail) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "auto load fail : Use Default value!\n");
+               for (path = 0; path < MAX_RF_PATH; path++) {
+                       /* 2.4G default value */
+                       for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
+                               pw2g->index_cck_base[path][group] = 0x2D;
+                               pw2g->index_bw40_base[path][group] = 0x2D;
+                       }
+                       for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) {
+                               if (cnt == 0) {
+                                       pw2g->bw20_diff[path][0] = 0x02;
+                                       pw2g->ofdm_diff[path][0] = 0x04;
+                               } else {
+                                       pw2g->bw20_diff[path][cnt] = 0xFE;
+                                       pw2g->bw40_diff[path][cnt] = 0xFE;
+                                       pw2g->cck_diff[path][cnt] = 0xFE;
+                                       pw2g->ofdm_diff[path][cnt] = 0xFE;
+                               }
+                       }
+               }
+               return;
+       }
+       for (path = 0; path < MAX_RF_PATH; path++) {
+               /*2.4G default value*/
+               for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
+                       pw2g->index_cck_base[path][group] = hwinfo[addr++];
+                       if (pw2g->index_cck_base[path][group] == 0xFF)
+                               pw2g->index_cck_base[path][group] = 0x2D;
+               }
+               for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) {
+                       pw2g->index_bw40_base[path][group] = hwinfo[addr++];
+                       if (pw2g->index_bw40_base[path][group] == 0xFF)
+                               pw2g->index_bw40_base[path][group] = 0x2D;
+               }
+               for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) {
+                       if (cnt == 0) {
+                               pw2g->bw40_diff[path][cnt] = 0;
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw2g->bw20_diff[path][cnt] = 0x02;
+                               } else {
+                                       pw2g->bw20_diff[path][cnt] =
+                                               (hwinfo[addr] & 0xf0) >> 4;
+                                       /*bit sign number to 8 bit sign number*/
+                                       if (pw2g->bw20_diff[path][cnt] & BIT(3))
+                                               pw2g->bw20_diff[path][cnt] |= 0xF0;
+                               }
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw2g->ofdm_diff[path][cnt] = 0x04;
+                               } else {
+                                       pw2g->ofdm_diff[path][cnt] =
+                                                       (hwinfo[addr] & 0x0f);
+                                       /*bit sign number to 8 bit sign number*/
+                                       if (pw2g->ofdm_diff[path][cnt] & BIT(3))
+                                               pw2g->ofdm_diff[path][cnt] |=
+                                                                         0xF0;
+                               }
+                               pw2g->cck_diff[path][cnt] = 0;
+                               addr++;
+                       } else {
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw2g->bw40_diff[path][cnt] = 0xFE;
+                               } else {
+                                       pw2g->bw40_diff[path][cnt] =
+                                               (hwinfo[addr] & 0xf0) >> 4;
+                                       if (pw2g->bw40_diff[path][cnt] & BIT(3))
+                                               pw2g->bw40_diff[path][cnt] |=
+                                                                         0xF0;
+                               }
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw2g->bw20_diff[path][cnt] = 0xFE;
+                               } else {
+                                       pw2g->bw20_diff[path][cnt] =
+                                                       (hwinfo[addr] & 0x0f);
+                                       if (pw2g->bw20_diff[path][cnt] & BIT(3))
+                                               pw2g->bw20_diff[path][cnt] |=
+                                                                         0xF0;
+                               }
+                               addr++;
+
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw2g->ofdm_diff[path][cnt] = 0xFE;
+                               } else {
+                                       pw2g->ofdm_diff[path][cnt] =
+                                               (hwinfo[addr] & 0xf0) >> 4;
+                                       if (pw2g->ofdm_diff[path][cnt] & BIT(3))
+                                               pw2g->ofdm_diff[path][cnt] |=
+                                                                         0xF0;
+                               }
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw2g->cck_diff[path][cnt] = 0xFE;
+                               } else {
+                                       pw2g->cck_diff[path][cnt] =
+                                                       (hwinfo[addr] & 0x0f);
+                                       if (pw2g->cck_diff[path][cnt] & BIT(3))
+                                               pw2g->cck_diff[path][cnt] |=
+                                                                        0xF0;
+                               }
+                               addr++;
+                       }
+               }
+               /*5G default value*/
+               for (group = 0; group < MAX_CHNL_GROUP_5G; group++) {
+                       pw5g->index_bw40_base[path][group] = hwinfo[addr++];
+                       if (pw5g->index_bw40_base[path][group] == 0xFF)
+                               pw5g->index_bw40_base[path][group] = 0xFE;
+               }
+               for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) {
+                       if (cnt == 0) {
+                               pw5g->bw40_diff[path][cnt] = 0;
+
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw5g->bw20_diff[path][cnt] = 0;
+                               } else {
+                                       pw5g->bw20_diff[path][0] =
+                                               (hwinfo[addr] & 0xf0) >> 4;
+                                       if (pw5g->bw20_diff[path][cnt] & BIT(3))
+                                               pw5g->bw20_diff[path][cnt] |=
+                                                                         0xF0;
+                               }
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw5g->ofdm_diff[path][cnt] = 0x04;
+                               } else {
+                                       pw5g->ofdm_diff[path][0] =
+                                                       (hwinfo[addr] & 0x0f);
+                                       if (pw5g->ofdm_diff[path][cnt] & BIT(3))
+                                               pw5g->ofdm_diff[path][cnt] |=
+                                                                         0xF0;
+                               }
+                               addr++;
+                       } else {
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw5g->bw40_diff[path][cnt] = 0xFE;
+                               } else {
+                                       pw5g->bw40_diff[path][cnt] =
+                                               (hwinfo[addr] & 0xf0) >> 4;
+                                       if (pw5g->bw40_diff[path][cnt] & BIT(3))
+                                               pw5g->bw40_diff[path][cnt] |= 0xF0;
+                               }
+                               if (hwinfo[addr] == 0xFF) {
+                                       pw5g->bw20_diff[path][cnt] = 0xFE;
+                               } else {
+                                       pw5g->bw20_diff[path][cnt] =
+                                                       (hwinfo[addr] & 0x0f);
+                                       if (pw5g->bw20_diff[path][cnt] & BIT(3))
+                                               pw5g->bw20_diff[path][cnt] |= 0xF0;
+                               }
+                               addr++;
+                       }
+               }
+               if (hwinfo[addr] == 0xFF) {
+                       pw5g->ofdm_diff[path][1] = 0xFE;
+                       pw5g->ofdm_diff[path][2] = 0xFE;
+               } else {
+                       pw5g->ofdm_diff[path][1] = (hwinfo[addr] & 0xf0) >> 4;
+                       pw5g->ofdm_diff[path][2] = (hwinfo[addr] & 0x0f);
+               }
+               addr++;
+
+               if (hwinfo[addr] == 0xFF)
+                       pw5g->ofdm_diff[path][3] = 0xFE;
+               else
+                       pw5g->ofdm_diff[path][3] = (hwinfo[addr] & 0x0f);
+               addr++;
+
+               for (cnt = 1; cnt < MAX_TX_COUNT; cnt++) {
+                       if (pw5g->ofdm_diff[path][cnt] == 0xFF)
+                               pw5g->ofdm_diff[path][cnt] = 0xFE;
+                       else if (pw5g->ofdm_diff[path][cnt] & BIT(3))
+                               pw5g->ofdm_diff[path][cnt] |= 0xF0;
+               }
+       }
+}
+
+static void _rtl8723be_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+                                                  bool autoload_fail,
+                                                  u8 *hwinfo)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct txpower_info_2g pw2g;
+       struct txpower_info_5g pw5g;
+       u8 rf_path, index;
+       u8 i;
+
+       _rtl8723be_read_power_value_fromprom(hw, &pw2g, &pw5g, autoload_fail,
+                                            hwinfo);
+
+       for (rf_path = 0; rf_path < 2; rf_path++) {
+               for (i = 0; i < 14; i++) {
+                       index = _rtl8723be_get_chnl_group(i+1);
+
+                       rtlefuse->txpwrlevel_cck[rf_path][i] =
+                                       pw2g.index_cck_base[rf_path][index];
+                       rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+                                       pw2g.index_bw40_base[rf_path][index];
+               }
+               for (i = 0; i < MAX_TX_COUNT; i++) {
+                       rtlefuse->txpwr_ht20diff[rf_path][i] =
+                                               pw2g.bw20_diff[rf_path][i];
+                       rtlefuse->txpwr_ht40diff[rf_path][i] =
+                                               pw2g.bw40_diff[rf_path][i];
+                       rtlefuse->txpwr_legacyhtdiff[rf_path][i] =
+                                               pw2g.ofdm_diff[rf_path][i];
+               }
+               for (i = 0; i < 14; i++) {
+                       RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+                               "RF(%d)-Ch(%d) [CCK / HT40_1S ] = "
+                               "[0x%x / 0x%x ]\n", rf_path, i,
+                               rtlefuse->txpwrlevel_cck[rf_path][i],
+                               rtlefuse->txpwrlevel_ht40_1s[rf_path][i]);
+               }
+       }
+       if (!autoload_fail)
+               rtlefuse->eeprom_thermalmeter =
+                                       hwinfo[EEPROM_THERMAL_METER_88E];
+       else
+               rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+
+       if (rtlefuse->eeprom_thermalmeter == 0xff || autoload_fail) {
+               rtlefuse->apk_thermalmeterignore = true;
+               rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+       }
+       rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
+       RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+               "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
+
+       if (!autoload_fail) {
+               rtlefuse->eeprom_regulatory =
+                       hwinfo[EEPROM_RF_BOARD_OPTION_88E] & 0x07;/*bit0~2*/
+               if (hwinfo[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
+                       rtlefuse->eeprom_regulatory = 0;
+       } else {
+               rtlefuse->eeprom_regulatory = 0;
+       }
+       RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+               "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
+}
+
+static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw,
+                                        bool pseudo_test)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u16 i, usvalue;
+       u8 hwinfo[HWSET_MAX_SIZE];
+       u16 eeprom_id;
+       bool is_toshiba_smid1 = false;
+       bool is_toshiba_smid2 = false;
+       bool is_samsung_smid = false;
+       bool is_lenovo_smid = false;
+       u16 toshiba_smid1[] = {
+               0x6151, 0x6152, 0x6154, 0x6155, 0x6177, 0x6178, 0x6179, 0x6180,
+               0x7151, 0x7152, 0x7154, 0x7155, 0x7177, 0x7178, 0x7179, 0x7180,
+               0x8151, 0x8152, 0x8154, 0x8155, 0x8181, 0x8182, 0x8184, 0x8185,
+               0x9151, 0x9152, 0x9154, 0x9155, 0x9181, 0x9182, 0x9184, 0x9185
+       };
+       u16 toshiba_smid2[] = {
+               0x6181, 0x6184, 0x6185, 0x7181, 0x7182, 0x7184, 0x7185, 0x8181,
+               0x8182, 0x8184, 0x8185, 0x9181, 0x9182, 0x9184, 0x9185
+       };
+       u16 samsung_smid[] = {
+               0x6191, 0x6192, 0x6193, 0x7191, 0x7192, 0x7193, 0x8191, 0x8192,
+               0x8193, 0x9191, 0x9192, 0x9193
+       };
+       u16 lenovo_smid[] = {
+               0x8195, 0x9195, 0x7194, 0x8200, 0x8201, 0x8202, 0x9199, 0x9200
+       };
+
+       if (pseudo_test) {
+               /* needs to be added */
+               return;
+       }
+       if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+               rtl_efuse_shadow_map_update(hw);
+
+               memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+                      HWSET_MAX_SIZE);
+       } else if (rtlefuse->epromtype == EEPROM_93C46) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "RTL819X Not boot from eeprom, check it !!");
+       }
+       RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
+                     hwinfo, HWSET_MAX_SIZE);
+
+       eeprom_id = *((u16 *)&hwinfo[0]);
+       if (eeprom_id != RTL8723BE_EEPROM_ID) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "EEPROM ID(%#x) is invalid!!\n", eeprom_id);
+               rtlefuse->autoload_failflag = true;
+       } else {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+               rtlefuse->autoload_failflag = false;
+       }
+       if (rtlefuse->autoload_failflag)
+               return;
+
+       rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+       rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+       rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+       rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROMId = 0x%4x\n", eeprom_id);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
+
+       for (i = 0; i < 6; i += 2) {
+               usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+               *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue;
+       }
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "dev_addr: %pM\n",
+                rtlefuse->dev_addr);
+
+       /*parse xtal*/
+       rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8723BE];
+       if (rtlefuse->crystalcap == 0xFF)
+               rtlefuse->crystalcap = 0x20;
+
+       _rtl8723be_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
+                                              hwinfo);
+
+       rtl8723be_read_bt_coexist_info_from_hwpg(hw,
+                                                rtlefuse->autoload_failflag,
+                                                hwinfo);
+
+       rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+       rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
+       rtlefuse->txpwr_fromeprom = true;
+       rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
+
+       /* set channel plan to world wide 13 */
+       rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+
+       if (rtlhal->oem_id == RT_CID_DEFAULT) {
+               /* Does this one have a Toshiba SMID from group 1? */
+               for (i = 0; i < sizeof(toshiba_smid1) / sizeof(u16); i++) {
+                       if (rtlefuse->eeprom_smid == toshiba_smid1[i]) {
+                               is_toshiba_smid1 = true;
+                               break;
+                       }
+               }
+               /* Does this one have a Toshiba SMID from group 2? */
+               for (i = 0; i < sizeof(toshiba_smid2) / sizeof(u16); i++) {
+                       if (rtlefuse->eeprom_smid == toshiba_smid2[i]) {
+                               is_toshiba_smid2 = true;
+                               break;
+                       }
+               }
+               /* Does this one have a Samsung SMID? */
+               for (i = 0; i < sizeof(samsung_smid) / sizeof(u16); i++) {
+                       if (rtlefuse->eeprom_smid == samsung_smid[i]) {
+                               is_samsung_smid = true;
+                               break;
+                       }
+               }
+               /* Does this one have a Lenovo SMID? */
+               for (i = 0; i < sizeof(lenovo_smid) / sizeof(u16); i++) {
+                       if (rtlefuse->eeprom_smid == lenovo_smid[i]) {
+                               is_lenovo_smid = true;
+                               break;
+                       }
+               }
+               switch (rtlefuse->eeprom_oemid) {
+               case EEPROM_CID_DEFAULT:
+                       if (rtlefuse->eeprom_did == 0x8176) {
+                               if (rtlefuse->eeprom_svid == 0x10EC &&
+                                   is_toshiba_smid1) {
+                                       rtlhal->oem_id = RT_CID_TOSHIBA;
+                               } else if (rtlefuse->eeprom_svid == 0x1025) {
+                                       rtlhal->oem_id = RT_CID_819X_ACER;
+                               } else if (rtlefuse->eeprom_svid == 0x10EC &&
+                                          is_samsung_smid) {
+                                       rtlhal->oem_id = RT_CID_819X_SAMSUNG;
+                               } else if (rtlefuse->eeprom_svid == 0x10EC &&
+                                          is_lenovo_smid) {
+                                       rtlhal->oem_id = RT_CID_819X_LENOVO;
+                               } else if ((rtlefuse->eeprom_svid == 0x10EC &&
+                                           rtlefuse->eeprom_smid == 0x8197) ||
+                                          (rtlefuse->eeprom_svid == 0x10EC &&
+                                           rtlefuse->eeprom_smid == 0x9196)) {
+                                       rtlhal->oem_id = RT_CID_819X_CLEVO;
+                               } else if ((rtlefuse->eeprom_svid == 0x1028 &&
+                                           rtlefuse->eeprom_smid == 0x8194) ||
+                                          (rtlefuse->eeprom_svid == 0x1028 &&
+                                           rtlefuse->eeprom_smid == 0x8198) ||
+                                          (rtlefuse->eeprom_svid == 0x1028 &&
+                                           rtlefuse->eeprom_smid == 0x9197) ||
+                                          (rtlefuse->eeprom_svid == 0x1028 &&
+                                           rtlefuse->eeprom_smid == 0x9198)) {
+                                       rtlhal->oem_id = RT_CID_819X_DELL;
+                               } else if ((rtlefuse->eeprom_svid == 0x103C &&
+                                           rtlefuse->eeprom_smid == 0x1629)) {
+                                       rtlhal->oem_id = RT_CID_819X_HP;
+                               } else if ((rtlefuse->eeprom_svid == 0x1A32 &&
+                                          rtlefuse->eeprom_smid == 0x2315)) {
+                                       rtlhal->oem_id = RT_CID_819X_QMI;
+                               } else if ((rtlefuse->eeprom_svid == 0x10EC &&
+                                          rtlefuse->eeprom_smid == 0x8203)) {
+                                       rtlhal->oem_id = RT_CID_819X_PRONETS;
+                               } else if ((rtlefuse->eeprom_svid == 0x1043 &&
+                                          rtlefuse->eeprom_smid == 0x84B5)) {
+                                       rtlhal->oem_id = RT_CID_819X_EDIMAX_ASUS;
+                               } else {
+                                       rtlhal->oem_id = RT_CID_DEFAULT;
+                               }
+                       } else if (rtlefuse->eeprom_did == 0x8178) {
+                               if (rtlefuse->eeprom_svid == 0x10EC &&
+                                   is_toshiba_smid2)
+                                       rtlhal->oem_id = RT_CID_TOSHIBA;
+                               else if (rtlefuse->eeprom_svid == 0x1025)
+                                       rtlhal->oem_id = RT_CID_819X_ACER;
+                               else if ((rtlefuse->eeprom_svid == 0x10EC &&
+                                         rtlefuse->eeprom_smid == 0x8186))
+                                       rtlhal->oem_id = RT_CID_819X_PRONETS;
+                               else if ((rtlefuse->eeprom_svid == 0x1043 &&
+                                         rtlefuse->eeprom_smid == 0x84B6))
+                                       rtlhal->oem_id =
+                                                       RT_CID_819X_EDIMAX_ASUS;
+                               else
+                                       rtlhal->oem_id = RT_CID_DEFAULT;
+                       } else {
+                                       rtlhal->oem_id = RT_CID_DEFAULT;
+                       }
+                       break;
+               case EEPROM_CID_TOSHIBA:
+                       rtlhal->oem_id = RT_CID_TOSHIBA;
+                       break;
+               case EEPROM_CID_CCX:
+                       rtlhal->oem_id = RT_CID_CCX;
+                       break;
+               case EEPROM_CID_QMI:
+                       rtlhal->oem_id = RT_CID_819X_QMI;
+                       break;
+               case EEPROM_CID_WHQL:
+                       break;
+               default:
+                       rtlhal->oem_id = RT_CID_DEFAULT;
+                       break;
+               }
+       }
+}
+
+static void _rtl8723be_hal_customized_behavior(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       pcipriv->ledctl.led_opendrain = true;
+       switch (rtlhal->oem_id) {
+       case RT_CID_819X_HP:
+               pcipriv->ledctl.led_opendrain = true;
+               break;
+       case RT_CID_819X_LENOVO:
+       case RT_CID_DEFAULT:
+       case RT_CID_TOSHIBA:
+       case RT_CID_CCX:
+       case RT_CID_819X_ACER:
+       case RT_CID_WHQL:
+       default:
+               break;
+       }
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                "RT Customized ID: 0x%02X\n", rtlhal->oem_id);
+}
+
+void rtl8723be_read_eeprom_info(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 tmp_u1b;
+
+       rtlhal->version = _rtl8723be_read_chip_version(hw);
+       if (get_rf_type(rtlphy) == RF_1T1R)
+               rtlpriv->dm.rfpath_rxenable[0] = true;
+       else
+               rtlpriv->dm.rfpath_rxenable[0] =
+                   rtlpriv->dm.rfpath_rxenable[1] = true;
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n",
+                rtlhal->version);
+       tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
+       if (tmp_u1b & BIT(4)) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n");
+               rtlefuse->epromtype = EEPROM_93C46;
+       } else {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n");
+               rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+       }
+       if (tmp_u1b & BIT(5)) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+               rtlefuse->autoload_failflag = false;
+               _rtl8723be_read_adapter_info(hw, false);
+       } else {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
+       }
+       _rtl8723be_hal_customized_behavior(hw);
+}
+
+static void rtl8723be_update_hal_rate_table(struct ieee80211_hw *hw,
+                                           struct ieee80211_sta *sta)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u32 ratr_value;
+       u8 ratr_index = 0;
+       u8 nmode = mac->ht_enable;
+       u8 mimo_ps = IEEE80211_SMPS_OFF;
+       u16 shortgi_rate;
+       u32 tmp_ratr_value;
+       u8 curtxbw_40mhz = mac->bw_40;
+       u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+                              1 : 0;
+       u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+                              1 : 0;
+       enum wireless_mode wirelessmode = mac->mode;
+
+       if (rtlhal->current_bandtype == BAND_ON_5G)
+               ratr_value = sta->supp_rates[1] << 4;
+       else
+               ratr_value = sta->supp_rates[0];
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               ratr_value = 0xfff;
+       ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+                      sta->ht_cap.mcs.rx_mask[0] << 12);
+       switch (wirelessmode) {
+       case WIRELESS_MODE_B:
+               if (ratr_value & 0x0000000c)
+                       ratr_value &= 0x0000000d;
+               else
+                       ratr_value &= 0x0000000f;
+               break;
+       case WIRELESS_MODE_G:
+               ratr_value &= 0x00000FF5;
+               break;
+       case WIRELESS_MODE_N_24G:
+       case WIRELESS_MODE_N_5G:
+               nmode = 1;
+               if (mimo_ps == IEEE80211_SMPS_STATIC) {
+                       ratr_value &= 0x0007F005;
+               } else {
+                       u32 ratr_mask;
+
+                       if (get_rf_type(rtlphy) == RF_1T2R ||
+                           get_rf_type(rtlphy) == RF_1T1R)
+                               ratr_mask = 0x000ff005;
+                       else
+                               ratr_mask = 0x0f0ff005;
+                       ratr_value &= ratr_mask;
+               }
+               break;
+       default:
+               if (rtlphy->rf_type == RF_1T2R)
+                       ratr_value &= 0x000ff0ff;
+               else
+                       ratr_value &= 0x0f0ff0ff;
+               break;
+       }
+       if ((rtlpriv->btcoexist.bt_coexistence) &&
+           (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4) &&
+           (rtlpriv->btcoexist.bt_cur_state) &&
+           (rtlpriv->btcoexist.bt_ant_isolation) &&
+           ((rtlpriv->btcoexist.bt_service == BT_SCO) ||
+            (rtlpriv->btcoexist.bt_service == BT_BUSY)))
+               ratr_value &= 0x0fffcfc0;
+       else
+               ratr_value &= 0x0FFFFFFF;
+
+       if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) ||
+                     (!curtxbw_40mhz && curshortgi_20mhz))) {
+               ratr_value |= 0x10000000;
+               tmp_ratr_value = (ratr_value >> 12);
+
+               for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+                       if ((1 << shortgi_rate) & tmp_ratr_value)
+                               break;
+               }
+               shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+                              (shortgi_rate << 4) | (shortgi_rate);
+       }
+       rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+       RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+                "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0));
+}
+
+static u8 _rtl8723be_mrate_idx_to_arfr_id(struct ieee80211_hw *hw,
+                                         u8 rate_index)
+{
+       u8 ret = 0;
+
+       switch (rate_index) {
+       case RATR_INX_WIRELESS_NGB:
+               ret = 1;
+               break;
+       case RATR_INX_WIRELESS_N:
+       case RATR_INX_WIRELESS_NG:
+               ret = 5;
+               break;
+       case RATR_INX_WIRELESS_NB:
+               ret = 3;
+               break;
+       case RATR_INX_WIRELESS_GB:
+               ret = 6;
+               break;
+       case RATR_INX_WIRELESS_G:
+               ret = 7;
+               break;
+       case RATR_INX_WIRELESS_B:
+               ret = 8;
+               break;
+       default:
+               ret = 0;
+               break;
+       }
+       return ret;
+}
+
+static void rtl8723be_update_hal_rate_mask(struct ieee80211_hw *hw,
+                                          struct ieee80211_sta *sta,
+                                          u8 rssi_level)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_sta_info *sta_entry = NULL;
+       u32 ratr_bitmap;
+       u8 ratr_index;
+       u8 curtxbw_40mhz = (sta->ht_cap.cap &
+                           IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0;
+       u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+                              1 : 0;
+       u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+                              1 : 0;
+       enum wireless_mode wirelessmode = 0;
+       bool shortgi = false;
+       u8 rate_mask[7];
+       u8 macid = 0;
+       u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+       wirelessmode = sta_entry->wireless_mode;
+       if (mac->opmode == NL80211_IFTYPE_STATION ||
+           mac->opmode == NL80211_IFTYPE_MESH_POINT)
+               curtxbw_40mhz = mac->bw_40;
+       else if (mac->opmode == NL80211_IFTYPE_AP ||
+                mac->opmode == NL80211_IFTYPE_ADHOC)
+               macid = sta->aid + 1;
+
+       ratr_bitmap = sta->supp_rates[0];
+
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               ratr_bitmap = 0xfff;
+
+       ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+                       sta->ht_cap.mcs.rx_mask[0] << 12);
+       switch (wirelessmode) {
+       case WIRELESS_MODE_B:
+               ratr_index = RATR_INX_WIRELESS_B;
+               if (ratr_bitmap & 0x0000000c)
+                       ratr_bitmap &= 0x0000000d;
+               else
+                       ratr_bitmap &= 0x0000000f;
+               break;
+       case WIRELESS_MODE_G:
+               ratr_index = RATR_INX_WIRELESS_GB;
+
+               if (rssi_level == 1)
+                       ratr_bitmap &= 0x00000f00;
+               else if (rssi_level == 2)
+                       ratr_bitmap &= 0x00000ff0;
+               else
+                       ratr_bitmap &= 0x00000ff5;
+               break;
+       case WIRELESS_MODE_A:
+               ratr_index = RATR_INX_WIRELESS_A;
+               ratr_bitmap &= 0x00000ff0;
+               break;
+       case WIRELESS_MODE_N_24G:
+       case WIRELESS_MODE_N_5G:
+               ratr_index = RATR_INX_WIRELESS_NGB;
+
+               if (mimo_ps == IEEE80211_SMPS_STATIC  ||
+                   mimo_ps == IEEE80211_SMPS_DYNAMIC) {
+                       if (rssi_level == 1)
+                               ratr_bitmap &= 0x00070000;
+                       else if (rssi_level == 2)
+                               ratr_bitmap &= 0x0007f000;
+                       else
+                               ratr_bitmap &= 0x0007f005;
+               } else {
+                       if (rtlphy->rf_type == RF_1T1R) {
+                               if (curtxbw_40mhz) {
+                                       if (rssi_level == 1)
+                                               ratr_bitmap &= 0x000f0000;
+                                       else if (rssi_level == 2)
+                                               ratr_bitmap &= 0x000ff000;
+                                       else
+                                               ratr_bitmap &= 0x000ff015;
+                               } else {
+                                       if (rssi_level == 1)
+                                               ratr_bitmap &= 0x000f0000;
+                                       else if (rssi_level == 2)
+                                               ratr_bitmap &= 0x000ff000;
+                                       else
+                                               ratr_bitmap &= 0x000ff005;
+                               }
+                       } else {
+                               if (curtxbw_40mhz) {
+                                       if (rssi_level == 1)
+                                               ratr_bitmap &= 0x0f8f0000;
+                                       else if (rssi_level == 2)
+                                               ratr_bitmap &= 0x0f8ff000;
+                                       else
+                                               ratr_bitmap &= 0x0f8ff015;
+                               } else {
+                                       if (rssi_level == 1)
+                                               ratr_bitmap &= 0x0f8f0000;
+                                       else if (rssi_level == 2)
+                                               ratr_bitmap &= 0x0f8ff000;
+                                       else
+                                               ratr_bitmap &= 0x0f8ff005;
+                               }
+                       }
+               }
+               if ((curtxbw_40mhz && curshortgi_40mhz) ||
+                   (!curtxbw_40mhz && curshortgi_20mhz)) {
+                       if (macid == 0)
+                               shortgi = true;
+                       else if (macid == 1)
+                               shortgi = false;
+               }
+               break;
+       default:
+               ratr_index = RATR_INX_WIRELESS_NGB;
+
+               if (rtlphy->rf_type == RF_1T2R)
+                       ratr_bitmap &= 0x000ff0ff;
+               else
+                       ratr_bitmap &= 0x0f0ff0ff;
+               break;
+       }
+       sta_entry->ratr_index = ratr_index;
+
+       RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+                "ratr_bitmap :%x\n", ratr_bitmap);
+       *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | (ratr_index << 28);
+       rate_mask[0] = macid;
+       rate_mask[1] = _rtl8723be_mrate_idx_to_arfr_id(hw, ratr_index) |
+                                                      (shortgi ? 0x80 : 0x00);
+       rate_mask[2] = curtxbw_40mhz;
+       /* if (prox_priv->proxim_modeinfo->power_output > 0)
+        *      rate_mask[2] |= BIT(6);
+        */
+
+       rate_mask[3] = (u8)(ratr_bitmap & 0x000000ff);
+       rate_mask[4] = (u8)((ratr_bitmap & 0x0000ff00) >> 8);
+       rate_mask[5] = (u8)((ratr_bitmap & 0x00ff0000) >> 16);
+       rate_mask[6] = (u8)((ratr_bitmap & 0xff000000) >> 24);
+
+       RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+                "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x:%x:%x\n",
+                ratr_index, ratr_bitmap,
+                rate_mask[0], rate_mask[1],
+                rate_mask[2], rate_mask[3],
+                rate_mask[4], rate_mask[5],
+                rate_mask[6]);
+       rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_RA_MASK, 7, rate_mask);
+       _rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0);
+}
+
+void rtl8723be_update_hal_rate_tbl(struct ieee80211_hw *hw,
+                                  struct ieee80211_sta *sta,
+                                  u8 rssi_level)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       if (rtlpriv->dm.useramask)
+               rtl8723be_update_hal_rate_mask(hw, sta, rssi_level);
+       else
+               rtl8723be_update_hal_rate_table(hw, sta);
+}
+
+void rtl8723be_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u16 sifs_timer;
+
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+                                     (u8 *)&mac->slot_time);
+       if (!mac->ht_enable)
+               sifs_timer = 0x0a0a;
+       else
+               sifs_timer = 0x0e0e;
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+}
+
+bool rtl8723be_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
+       u8 u1tmp;
+       bool actuallyset = false;
+
+       if (rtlpriv->rtlhal.being_init_adapter)
+               return false;
+
+       if (ppsc->swrf_processing)
+               return false;
+
+       spin_lock(&rtlpriv->locks.rf_ps_lock);
+       if (ppsc->rfchange_inprogress) {
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+               return false;
+       } else {
+               ppsc->rfchange_inprogress = true;
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+       }
+       cur_rfstate = ppsc->rfpwr_state;
+
+       rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
+                      rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2) & ~(BIT(1)));
+
+       u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL_2);
+
+       if (rtlphy->polarity_ctl)
+               e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFOFF : ERFON;
+       else
+               e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFON : ERFOFF;
+
+       if (ppsc->hwradiooff &&
+           (e_rfpowerstate_toset == ERFON)) {
+               RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                        "GPIOChangeRF  - HW Radio ON, RF ON\n");
+
+               e_rfpowerstate_toset = ERFON;
+               ppsc->hwradiooff = false;
+               actuallyset = true;
+       } else if (!ppsc->hwradiooff &&
+                  (e_rfpowerstate_toset == ERFOFF)) {
+               RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                        "GPIOChangeRF  - HW Radio OFF, RF OFF\n");
+
+               e_rfpowerstate_toset = ERFOFF;
+               ppsc->hwradiooff = true;
+               actuallyset = true;
+       }
+       if (actuallyset) {
+               spin_lock(&rtlpriv->locks.rf_ps_lock);
+               ppsc->rfchange_inprogress = false;
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+       } else {
+               if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC)
+                       RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+               spin_lock(&rtlpriv->locks.rf_ps_lock);
+               ppsc->rfchange_inprogress = false;
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+       }
+       *valid = 1;
+       return !ppsc->hwradiooff;
+}
+
+void rtl8723be_set_key(struct ieee80211_hw *hw, u32 key_index,
+                      u8 *p_macaddr, bool is_group, u8 enc_algo,
+                      bool is_wepkey, bool clear_all)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 *macaddr = p_macaddr;
+       u32 entry_id = 0;
+       bool is_pairwise = false;
+
+       static u8 cam_const_addr[4][6] = {
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+       };
+       static u8 cam_const_broad[] = {
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+       };
+
+       if (clear_all) {
+               u8 idx = 0;
+               u8 cam_offset = 0;
+               u8 clear_number = 5;
+
+               RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n");
+
+               for (idx = 0; idx < clear_number; idx++) {
+                       rtl_cam_mark_invalid(hw, cam_offset + idx);
+                       rtl_cam_empty_entry(hw, cam_offset + idx);
+
+                       if (idx < 5) {
+                               memset(rtlpriv->sec.key_buf[idx], 0,
+                                      MAX_KEY_LEN);
+                               rtlpriv->sec.key_len[idx] = 0;
+                       }
+               }
+       } else {
+               switch (enc_algo) {
+               case WEP40_ENCRYPTION:
+                       enc_algo = CAM_WEP40;
+                       break;
+               case WEP104_ENCRYPTION:
+                       enc_algo = CAM_WEP104;
+                       break;
+               case TKIP_ENCRYPTION:
+                       enc_algo = CAM_TKIP;
+                       break;
+               case AESCCMP_ENCRYPTION:
+                       enc_algo = CAM_AES;
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not process\n");
+                       enc_algo = CAM_TKIP;
+                       break;
+               }
+
+               if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+                       macaddr = cam_const_addr[key_index];
+                       entry_id = key_index;
+               } else {
+                       if (is_group) {
+                               macaddr = cam_const_broad;
+                               entry_id = key_index;
+                       } else {
+                               if (mac->opmode == NL80211_IFTYPE_AP) {
+                                       entry_id = rtl_cam_get_free_entry(hw,
+                                                               p_macaddr);
+                                       if (entry_id >=  TOTAL_CAM_ENTRY) {
+                                               RT_TRACE(rtlpriv, COMP_SEC,
+                                                        DBG_EMERG,
+                                                        "Can not find free"
+                                                        " hw security cam "
+                                                        "entry\n");
+                                               return;
+                                       }
+                               } else {
+                                       entry_id = CAM_PAIRWISE_KEY_POSITION;
+                               }
+                               key_index = PAIRWISE_KEYIDX;
+                               is_pairwise = true;
+                       }
+               }
+               if (rtlpriv->sec.key_len[key_index] == 0) {
+                       RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                                "delete one entry, entry_id is %d\n",
+                                entry_id);
+                       if (mac->opmode == NL80211_IFTYPE_AP)
+                               rtl_cam_del_entry(hw, p_macaddr);
+                       rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
+               } else {
+                       RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                                "add one entry\n");
+                       if (is_pairwise) {
+                               RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                                        "set Pairwise key\n");
+
+                               rtl_cam_add_one_entry(hw, macaddr, key_index,
+                                                     entry_id, enc_algo,
+                                                     CAM_CONFIG_NO_USEDK,
+                                                     rtlpriv->sec.key_buf[key_index]);
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                                        "set group key\n");
+
+                               if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+                                       rtl_cam_add_one_entry(hw,
+                                               rtlefuse->dev_addr,
+                                               PAIRWISE_KEYIDX,
+                                               CAM_PAIRWISE_KEY_POSITION,
+                                               enc_algo,
+                                               CAM_CONFIG_NO_USEDK,
+                                               rtlpriv->sec.key_buf
+                                               [entry_id]);
+                               }
+                               rtl_cam_add_one_entry(hw, macaddr, key_index,
+                                                     entry_id, enc_algo,
+                                                     CAM_CONFIG_NO_USEDK,
+                                                     rtlpriv->sec.key_buf[entry_id]);
+                       }
+               }
+       }
+}
+
+void rtl8723be_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+                                             bool auto_load_fail, u8 *hwinfo)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 value;
+       u32 tmpu_32;
+
+       if (!auto_load_fail) {
+               tmpu_32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL);
+               if (tmpu_32 & BIT(18))
+                       rtlpriv->btcoexist.btc_info.btcoexist = 1;
+               else
+                       rtlpriv->btcoexist.btc_info.btcoexist = 0;
+               value = hwinfo[RF_OPTION4];
+               rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8723B;
+               rtlpriv->btcoexist.btc_info.ant_num = (value & 0x1);
+       } else {
+               rtlpriv->btcoexist.btc_info.btcoexist = 0;
+               rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8723B;
+               rtlpriv->btcoexist.btc_info.ant_num = ANT_X2;
+       }
+}
+
+void rtl8723be_bt_reg_init(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       /* 0:Low, 1:High, 2:From Efuse. */
+       rtlpriv->btcoexist.reg_bt_iso = 2;
+       /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
+       rtlpriv->btcoexist.reg_bt_sco = 3;
+       /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+       rtlpriv->btcoexist.reg_bt_sco = 0;
+}
+
+void rtl8723be_bt_hw_init(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->cfg->ops->get_btc_status())
+               rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv);
+}
+
+void rtl8723be_suspend(struct ieee80211_hw *hw)
+{
+}
+
+void rtl8723be_resume(struct ieee80211_hw *hw)
+{
+}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl8723be_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da,
+                                 bool write_into_reg)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       if (allow_all_da) /* Set BIT0 */
+               rtlpci->receive_config |= RCR_AAP;
+       else /* Clear BIT0 */
+               rtlpci->receive_config &= ~RCR_AAP;
+
+       if (write_into_reg)
+               rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+       RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+                "receive_config = 0x%08X, write_into_reg =%d\n",
+                rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.h b/drivers/net/wireless/rtlwifi/rtl8723be/hw.h
new file mode 100644 (file)
index 0000000..b7449a9
--- /dev/null
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_HW_H__
+#define __RTL8723BE_HW_H__
+
+void rtl8723be_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8723be_read_eeprom_info(struct ieee80211_hw *hw);
+
+void rtl8723be_interrupt_recognized(struct ieee80211_hw *hw,
+                                   u32 *p_inta, u32 *p_intb);
+int rtl8723be_hw_init(struct ieee80211_hw *hw);
+void rtl8723be_card_disable(struct ieee80211_hw *hw);
+void rtl8723be_enable_interrupt(struct ieee80211_hw *hw);
+void rtl8723be_disable_interrupt(struct ieee80211_hw *hw);
+int rtl8723be_set_network_type(struct ieee80211_hw *hw,
+                              enum nl80211_iftype type);
+void rtl8723be_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl8723be_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl8723be_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl8723be_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl8723be_update_interrupt_mask(struct ieee80211_hw *hw,
+                                    u32 add_msr, u32 rm_msr);
+void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8723be_update_hal_rate_tbl(struct ieee80211_hw *hw,
+                                  struct ieee80211_sta *sta,
+                                  u8 rssi_level);
+void rtl8723be_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl8723be_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
+void rtl8723be_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl8723be_set_key(struct ieee80211_hw *hw, u32 key_index,
+                      u8 *p_macaddr, bool is_group, u8 enc_algo,
+                      bool is_wepkey, bool clear_all);
+void rtl8723be_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+                                             bool autoload_fail, u8 *hwinfo);
+void rtl8723be_bt_reg_init(struct ieee80211_hw *hw);
+void rtl8723be_bt_hw_init(struct ieee80211_hw *hw);
+void rtl8723be_suspend(struct ieee80211_hw *hw);
+void rtl8723be_resume(struct ieee80211_hw *hw);
+void rtl8723be_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da,
+                                 bool write_into_reg);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/led.c b/drivers/net/wireless/rtlwifi/rtl8723be/led.c
new file mode 100644 (file)
index 0000000..cb931a3
--- /dev/null
@@ -0,0 +1,153 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+static void _rtl8723be_init_led(struct ieee80211_hw *hw,  struct rtl_led *pled,
+                               enum rtl_led_pin ledpin)
+{
+       pled->hw = hw;
+       pled->ledpin = ledpin;
+       pled->ledon = false;
+}
+
+void rtl8723be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+       u8 ledcfg;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+                "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+
+       switch (pled->ledpin) {
+       case LED_PIN_GPIO0:
+               break;
+       case LED_PIN_LED0:
+               ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+               ledcfg &= ~BIT(6);
+               rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5));
+               break;
+       case LED_PIN_LED1:
+               ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+               rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       }
+       pled->ledon = true;
+}
+
+void rtl8723be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       u8 ledcfg;
+
+       RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+                "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+
+       ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+
+       switch (pled->ledpin) {
+       case LED_PIN_GPIO0:
+               break;
+       case LED_PIN_LED0:
+               ledcfg &= 0xf0;
+               if (pcipriv->ledctl.led_opendrain) {
+                       ledcfg &= 0x90; /* Set to software control. */
+                       rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3)));
+                       ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
+                       ledcfg &= 0xFE;
+                       rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg);
+               } else {
+                       ledcfg &= ~BIT(6);
+                       rtl_write_byte(rtlpriv, REG_LEDCFG2,
+                                      (ledcfg | BIT(3) | BIT(5)));
+               }
+               break;
+       case LED_PIN_LED1:
+               ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+               ledcfg &= 0x10; /* Set to software control. */
+               rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg|BIT(3));
+
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not processed\n");
+               break;
+       }
+       pled->ledon = false;
+}
+
+void rtl8723be_init_sw_leds(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       _rtl8723be_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
+       _rtl8723be_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
+}
+
+static void _rtl8723be_sw_led_control(struct ieee80211_hw *hw,
+                                     enum led_ctl_mode ledaction)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_led *pled0 = &(pcipriv->ledctl.sw_led0);
+       switch (ledaction) {
+       case LED_CTL_POWER_ON:
+       case LED_CTL_LINK:
+       case LED_CTL_NO_LINK:
+               rtl8723be_sw_led_on(hw, pled0);
+               break;
+       case LED_CTL_POWER_OFF:
+               rtl8723be_sw_led_off(hw, pled0);
+               break;
+       default:
+               break;
+       }
+}
+
+void rtl8723be_led_control(struct ieee80211_hw *hw,
+                          enum led_ctl_mode ledaction)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
+           (ledaction == LED_CTL_TX ||
+            ledaction == LED_CTL_RX ||
+            ledaction == LED_CTL_SITE_SURVEY ||
+            ledaction == LED_CTL_LINK ||
+            ledaction == LED_CTL_NO_LINK ||
+            ledaction == LED_CTL_START_TO_LINK ||
+            ledaction == LED_CTL_POWER_ON)) {
+               return;
+       }
+       RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n", ledaction);
+       _rtl8723be_sw_led_control(hw, ledaction);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/led.h b/drivers/net/wireless/rtlwifi/rtl8723be/led.h
new file mode 100644 (file)
index 0000000..c57de37
--- /dev/null
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_LED_H__
+#define __RTL8723BE_LED_H__
+
+void rtl8723be_init_sw_leds(struct ieee80211_hw *hw);
+void rtl8723be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8723be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8723be_led_control(struct ieee80211_hw *hw,
+                          enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c
new file mode 100644 (file)
index 0000000..1575ef9
--- /dev/null
@@ -0,0 +1,2156 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "../core.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "../rtl8723com/phy_common.h"
+#include "rf.h"
+#include "dm.h"
+#include "table.h"
+#include "trx.h"
+
+static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw);
+static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+                                                      u8 configtype);
+static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw,
+                                             u8 channel, u8 *stage,
+                                             u8 *step, u32 *delay);
+static bool _rtl8723be_check_condition(struct ieee80211_hw *hw,
+                                      const u32  condition)
+{
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u32 _board = rtlefuse->board_type; /*need efuse define*/
+       u32 _interface = rtlhal->interface;
+       u32 _platform = 0x08;/*SupportPlatform */
+       u32 cond = condition;
+
+       if (condition == 0xCDCDCDCD)
+               return true;
+
+       cond = condition & 0xFF;
+       if ((_board & cond) == 0 && cond != 0x1F)
+               return false;
+
+       cond = condition & 0xFF00;
+       cond = cond >> 8;
+       if ((_interface & cond) == 0 && cond != 0x07)
+               return false;
+
+       cond = condition & 0xFF0000;
+       cond = cond >> 16;
+       if ((_platform & cond) == 0 && cond != 0x0F)
+               return false;
+       return true;
+}
+
+static bool _rtl8723be_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 i;
+       u32 arraylength;
+       u32 *ptrarray;
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read rtl8723beMACPHY_Array\n");
+       arraylength = RTL8723BEMAC_1T_ARRAYLEN;
+       ptrarray = RTL8723BEMAC_1T_ARRAY;
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "Img:RTL8723bEMAC_1T_ARRAY LEN %d\n", arraylength);
+       for (i = 0; i < arraylength; i = i + 2)
+               rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
+       return true;
+}
+
+static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+                                                    u8 configtype)
+{
+       #define READ_NEXT_PAIR(v1, v2, i) \
+               do { \
+                       i += 2; \
+                       v1 = array_table[i];\
+                       v2 = array_table[i+1]; \
+               } while (0)
+
+       int i;
+       u32 *array_table;
+       u16 arraylen;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 v1 = 0, v2 = 0;
+
+       if (configtype == BASEBAND_CONFIG_PHY_REG) {
+               arraylen = RTL8723BEPHY_REG_1TARRAYLEN;
+               array_table = RTL8723BEPHY_REG_1TARRAY;
+
+               for (i = 0; i < arraylen; i = i + 2) {
+                       v1 = array_table[i];
+                       v2 = array_table[i+1];
+                       if (v1 < 0xcdcdcdcd) {
+                               rtl_bb_delay(hw, v1, v2);
+                       } else {/*This line is the start line of branch.*/
+                               if (!_rtl8723be_check_condition(hw, array_table[i])) {
+                                       /*Discard the following (offset, data) pairs*/
+                                       READ_NEXT_PAIR(v1, v2, i);
+                                       while (v2 != 0xDEAD &&
+                                              v2 != 0xCDEF &&
+                                              v2 != 0xCDCD &&
+                                              i < arraylen - 2) {
+                                               READ_NEXT_PAIR(v1, v2, i);
+                                       }
+                                       i -= 2; /* prevent from for-loop += 2*/
+                               /* Configure matched pairs and
+                                * skip to end of if-else.
+                                */
+                               } else {
+                                       READ_NEXT_PAIR(v1, v2, i);
+                                       while (v2 != 0xDEAD &&
+                                              v2 != 0xCDEF &&
+                                              v2 != 0xCDCD &&
+                                              i < arraylen - 2) {
+                                               rtl_bb_delay(hw,
+                                                                   v1, v2);
+                                               READ_NEXT_PAIR(v1, v2, i);
+                                       }
+
+                                       while (v2 != 0xDEAD && i < arraylen - 2)
+                                               READ_NEXT_PAIR(v1, v2, i);
+                               }
+                       }
+               }
+       } else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+               arraylen = RTL8723BEAGCTAB_1TARRAYLEN;
+               array_table = RTL8723BEAGCTAB_1TARRAY;
+
+               for (i = 0; i < arraylen; i = i + 2) {
+                       v1 = array_table[i];
+                       v2 = array_table[i+1];
+                       if (v1 < 0xCDCDCDCD) {
+                               rtl_set_bbreg(hw, array_table[i],
+                                             MASKDWORD,
+                                             array_table[i + 1]);
+                               udelay(1);
+                               continue;
+                       } else {/*This line is the start line of branch.*/
+                               if (!_rtl8723be_check_condition(hw, array_table[i])) {
+                                       /* Discard the following
+                                        * (offset, data) pairs
+                                        */
+                                       READ_NEXT_PAIR(v1, v2, i);
+                                       while (v2 != 0xDEAD &&
+                                              v2 != 0xCDEF &&
+                                              v2 != 0xCDCD &&
+                                              i < arraylen - 2) {
+                                               READ_NEXT_PAIR(v1, v2, i);
+                                       }
+                                       i -= 2; /* prevent from for-loop += 2*/
+                               /*Configure matched pairs and
+                                *skip to end of if-else.
+                                */
+                               } else {
+                                       READ_NEXT_PAIR(v1, v2, i);
+                                       while (v2 != 0xDEAD &&
+                                              v2 != 0xCDEF &&
+                                              v2 != 0xCDCD &&
+                                              i < arraylen - 2) {
+                                               rtl_set_bbreg(hw, array_table[i],
+                                                             MASKDWORD,
+                                                             array_table[i + 1]);
+                                               udelay(1);
+                                               READ_NEXT_PAIR(v1, v2, i);
+                                       }
+
+                                       while (v2 != 0xDEAD && i < arraylen - 2)
+                                               READ_NEXT_PAIR(v1, v2, i);
+                               }
+                       }
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                "The agctab_array_table[0] is "
+                                 "%x Rtl818EEPHY_REGArray[1] is %x\n",
+                                 array_table[i], array_table[i + 1]);
+               }
+       }
+       return true;
+}
+
+static u8 _rtl8723be_get_rate_section_index(u32 regaddr)
+{
+       u8 index = 0;
+
+       switch (regaddr) {
+       case RTXAGC_A_RATE18_06:
+       case RTXAGC_B_RATE18_06:
+               index = 0;
+               break;
+       case RTXAGC_A_RATE54_24:
+       case RTXAGC_B_RATE54_24:
+               index = 1;
+               break;
+       case RTXAGC_A_CCK1_MCS32:
+       case RTXAGC_B_CCK1_55_MCS32:
+               index = 2;
+               break;
+       case RTXAGC_B_CCK11_A_CCK2_11:
+               index = 3;
+               break;
+       case RTXAGC_A_MCS03_MCS00:
+       case RTXAGC_B_MCS03_MCS00:
+               index = 4;
+               break;
+       case RTXAGC_A_MCS07_MCS04:
+       case RTXAGC_B_MCS07_MCS04:
+               index = 5;
+               break;
+       case RTXAGC_A_MCS11_MCS08:
+       case RTXAGC_B_MCS11_MCS08:
+               index = 6;
+               break;
+       case RTXAGC_A_MCS15_MCS12:
+       case RTXAGC_B_MCS15_MCS12:
+               index = 7;
+               break;
+       default:
+               regaddr &= 0xFFF;
+               if (regaddr >= 0xC20 && regaddr <= 0xC4C)
+                       index = (u8) ((regaddr - 0xC20) / 4);
+               else if (regaddr >= 0xE20 && regaddr <= 0xE4C)
+                       index = (u8) ((regaddr - 0xE20) / 4);
+               break;
+       };
+       return index;
+}
+
+u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+                              u32 regaddr, u32 bitmask)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 original_value, readback_value, bitshift;
+       unsigned long flags;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
+                 regaddr, rfpath, bitmask);
+
+       spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+       original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr);
+       bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+       readback_value = (original_value & bitmask) >> bitshift;
+
+       spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), rfpath(%#x), "
+                 "bitmask(%#x), original_value(%#x)\n",
+                 regaddr, rfpath, bitmask, original_value);
+
+       return readback_value;
+}
+
+void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path path,
+                             u32 regaddr, u32 bitmask, u32 data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 original_value, bitshift;
+       unsigned long flags;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+                 regaddr, bitmask, data, path);
+
+       spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+       if (bitmask != RFREG_OFFSET_MASK) {
+                       original_value = rtl8723_phy_rf_serial_read(hw, path,
+                                                                   regaddr);
+                       bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+                       data = ((original_value & (~bitmask)) |
+                               (data << bitshift));
+               }
+
+       rtl8723_phy_rf_serial_write(hw, path, regaddr, data);
+
+       spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+                 regaddr, bitmask, data, path);
+}
+
+bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       bool rtstatus = _rtl8723be_phy_config_mac_with_headerfile(hw);
+
+       rtl_write_byte(rtlpriv, 0x04CA, 0x0B);
+       return rtstatus;
+}
+
+bool rtl8723be_phy_bb_config(struct ieee80211_hw *hw)
+{
+       bool rtstatus = true;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u16 regval;
+       u8 reg_hwparafile = 1;
+       u32 tmp;
+       u8 crystalcap = rtlpriv->efuse.crystalcap;
+       rtl8723_phy_init_bb_rf_reg_def(hw);
+       regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+       rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
+                      regval | BIT(13) | BIT(0) | BIT(1));
+
+       rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+                      FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
+                      FEN_BB_GLB_RSTN | FEN_BBRSTB);
+       tmp = rtl_read_dword(rtlpriv, 0x4c);
+       rtl_write_dword(rtlpriv, 0x4c, tmp | BIT(23));
+
+       rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
+
+       if (reg_hwparafile == 1)
+               rtstatus = _rtl8723be_phy_bb8723b_config_parafile(hw);
+
+       crystalcap = crystalcap & 0x3F;
+       rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+                     (crystalcap | crystalcap << 6));
+
+       return rtstatus;
+}
+
+bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw)
+{
+       return rtl8723be_phy_rf6052_config(hw);
+}
+
+static void _rtl8723be_config_rf_reg(struct ieee80211_hw *hw, u32 addr,
+                                    u32 data, enum radio_path rfpath,
+                                    u32 regaddr)
+{
+       if (addr == 0xfe || addr == 0xffe) {
+               mdelay(50);
+       } else {
+               rtl_set_rfreg(hw, rfpath, regaddr, RFREG_OFFSET_MASK, data);
+               udelay(1);
+       }
+}
+
+static void _rtl8723be_config_rf_radio_a(struct ieee80211_hw *hw,
+                                        u32 addr, u32 data)
+{
+       u32 content = 0x1000; /*RF Content: radio_a_txt*/
+       u32 maskforphyset = (u32)(content & 0xE000);
+
+       _rtl8723be_config_rf_reg(hw, addr, data, RF90_PATH_A,
+                                addr | maskforphyset);
+}
+
+static void _rtl8723be_phy_init_tx_power_by_rate(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       u8 band, path, txnum, section;
+
+       for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band)
+               for (path = 0; path < TX_PWR_BY_RATE_NUM_RF; ++path)
+                       for (txnum = 0; txnum < TX_PWR_BY_RATE_NUM_RF; ++txnum)
+                               for (section = 0;
+                                    section < TX_PWR_BY_RATE_NUM_SECTION;
+                                    ++section)
+                                       rtlphy->tx_power_by_rate_offset[band]
+                                               [path][txnum][section] = 0;
+}
+
+static void phy_set_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band,
+                                      u8 path, u8 rate_section,
+                                      u8 txnum, u8 value)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       if (path > RF90_PATH_D) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "Invalid Rf Path %d in phy_SetTxPowerByRatBase()\n",
+                         path);
+               return;
+       }
+
+       if (band == BAND_ON_2_4G) {
+               switch (rate_section) {
+               case CCK:
+                       rtlphy->txpwr_by_rate_base_24g[path][txnum][0] = value;
+                       break;
+               case OFDM:
+                       rtlphy->txpwr_by_rate_base_24g[path][txnum][1] = value;
+                       break;
+               case HT_MCS0_MCS7:
+                       rtlphy->txpwr_by_rate_base_24g[path][txnum][2] = value;
+                       break;
+               case HT_MCS8_MCS15:
+                       rtlphy->txpwr_by_rate_base_24g[path][txnum][3] = value;
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                "Invalid RateSection %d in Band 2.4G, Rf Path"
+                                 " %d, %dTx in PHY_SetTxPowerByRateBase()\n",
+                                 rate_section, path, txnum);
+                       break;
+               };
+       } else {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "Invalid Band %d in PHY_SetTxPowerByRateBase()\n",
+                         band);
+       }
+}
+
+static u8 phy_get_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band, u8 path,
+                                    u8 txnum, u8 rate_section)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 value = 0;
+       if (path > RF90_PATH_D) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "Invalid Rf Path %d in PHY_GetTxPowerByRateBase()\n",
+                         path);
+               return 0;
+       }
+
+       if (band == BAND_ON_2_4G) {
+               switch (rate_section) {
+               case CCK:
+                       value = rtlphy->txpwr_by_rate_base_24g[path][txnum][0];
+                       break;
+               case OFDM:
+                       value = rtlphy->txpwr_by_rate_base_24g[path][txnum][1];
+                       break;
+               case HT_MCS0_MCS7:
+                       value = rtlphy->txpwr_by_rate_base_24g[path][txnum][2];
+                       break;
+               case HT_MCS8_MCS15:
+                       value = rtlphy->txpwr_by_rate_base_24g[path][txnum][3];
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                "Invalid RateSection %d in Band 2.4G, Rf Path"
+                                 " %d, %dTx in PHY_GetTxPowerByRateBase()\n",
+                                 rate_section, path, txnum);
+                       break;
+               };
+       } else {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "Invalid Band %d in PHY_GetTxPowerByRateBase()\n",
+                         band);
+       }
+
+       return value;
+}
+
+static void _rtl8723be_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u16 raw_value = 0;
+       u8 base = 0, path = 0;
+
+       for (path = RF90_PATH_A; path <= RF90_PATH_B; ++path) {
+               if (path == RF90_PATH_A) {
+                       raw_value = (u16) (rtlphy->tx_power_by_rate_offset
+                               [BAND_ON_2_4G][path][RF_1TX][3] >> 24) & 0xFF;
+                       base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+                       phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, CCK,
+                                                  RF_1TX, base);
+               } else if (path == RF90_PATH_B) {
+                       raw_value = (u16) (rtlphy->tx_power_by_rate_offset
+                               [BAND_ON_2_4G][path][RF_1TX][3] >> 0) & 0xFF;
+                       base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+                       phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path,
+                                                  CCK, RF_1TX, base);
+               }
+               raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                                         [path][RF_1TX][1] >> 24) & 0xFF;
+               base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+               phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, OFDM, RF_1TX,
+                                          base);
+
+               raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                                         [path][RF_1TX][5] >> 24) & 0xFF;
+               base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+               phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, HT_MCS0_MCS7,
+                                          RF_1TX, base);
+
+               raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                                         [path][RF_2TX][7] >> 24) & 0xFF;
+               base = (raw_value >> 4) * 10 + (raw_value & 0xF);
+               phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path,
+                                          HT_MCS8_MCS15, RF_2TX, base);
+       }
+}
+
+static void phy_conv_dbm_to_rel(u32 *data, u8 start, u8 end, u8 base_val)
+{
+       char i = 0;
+       u8 temp_value = 0;
+       u32 temp_data = 0;
+
+       for (i = 3; i >= 0; --i) {
+               if (i >= start && i <= end) {
+                       /* Get the exact value */
+                       temp_value = (u8) (*data >> (i * 8)) & 0xF;
+                       temp_value += ((u8) ((*data >> (i*8 + 4)) & 0xF)) * 10;
+
+                       /* Change the value to a relative value */
+                       temp_value = (temp_value > base_val) ?
+                                    temp_value - base_val :
+                                    base_val - temp_value;
+               } else {
+                       temp_value = (u8) (*data >> (i * 8)) & 0xFF;
+               }
+               temp_data <<= 8;
+               temp_data |= temp_value;
+       }
+       *data = temp_data;
+}
+
+static void conv_dbm_to_rel(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 base = 0, rfpath = RF90_PATH_A;
+
+       base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
+                                         RF_1TX, CCK);
+       phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                           [rfpath][RF_1TX][2]), 1, 1, base);
+       phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                           [rfpath][RF_1TX][3]), 1, 3, base);
+
+       base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
+                                         RF_1TX, OFDM);
+       phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                           [rfpath][RF_1TX][0]), 0, 3, base);
+       phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                           [rfpath][RF_1TX][1]), 0, 3, base);
+
+       base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
+                                         RF_1TX, HT_MCS0_MCS7);
+       phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                           [rfpath][RF_1TX][4]), 0, 3, base);
+       phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                           [rfpath][RF_1TX][5]), 0, 3, base);
+
+       base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
+                                         RF_2TX, HT_MCS8_MCS15);
+       phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                           [rfpath][RF_2TX][6]), 0, 3, base);
+
+       phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
+                           [rfpath][RF_2TX][7]), 0, 3, base);
+
+       RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+                "<=== conv_dbm_to_rel()\n");
+}
+
+static void _rtl8723be_phy_txpower_by_rate_configuration(
+                                                       struct ieee80211_hw *hw)
+{
+       _rtl8723be_phy_store_txpower_by_rate_base(hw);
+       conv_dbm_to_rel(hw);
+}
+
+static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       bool rtstatus;
+
+       rtstatus = _rtl8723be_phy_config_bb_with_headerfile(hw,
+                                               BASEBAND_CONFIG_PHY_REG);
+       if (!rtstatus) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
+               return false;
+       }
+       _rtl8723be_phy_init_tx_power_by_rate(hw);
+       if (!rtlefuse->autoload_failflag) {
+               rtlphy->pwrgroup_cnt = 0;
+               rtstatus = _rtl8723be_phy_config_bb_with_pgheaderfile(hw,
+                                               BASEBAND_CONFIG_PHY_REG);
+       }
+       _rtl8723be_phy_txpower_by_rate_configuration(hw);
+       if (!rtstatus) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
+               return false;
+       }
+       rtstatus = _rtl8723be_phy_config_bb_with_headerfile(hw,
+                                               BASEBAND_CONFIG_AGC_TAB);
+       if (!rtstatus) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+               return false;
+       }
+       rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
+                                                      RFPGA0_XA_HSSIPARAMETER2,
+                                                      0x200));
+       return true;
+}
+
+static void _rtl8723be_store_tx_power_by_rate(struct ieee80211_hw *hw,
+                                             u32 band, u32 rfpath,
+                                             u32 txnum, u32 regaddr,
+                                             u32 bitmask, u32 data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 rate_section = _rtl8723be_get_rate_section_index(regaddr);
+
+       if (band != BAND_ON_2_4G && band != BAND_ON_5G) {
+               RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR,
+                        "Invalid Band %d\n", band);
+               return;
+       }
+
+       if (rfpath > TX_PWR_BY_RATE_NUM_RF) {
+               RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR,
+                        "Invalid RfPath %d\n", rfpath);
+               return;
+       }
+       if (txnum > TX_PWR_BY_RATE_NUM_RF) {
+               RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR,
+                        "Invalid TxNum %d\n", txnum);
+               return;
+       }
+       rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] =
+                                                                       data;
+}
+
+static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+                                                      u8 configtype)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i;
+       u32 *phy_regarray_table_pg;
+       u16 phy_regarray_pg_len;
+       u32 v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0, v6 = 0;
+
+       phy_regarray_pg_len = RTL8723BEPHY_REG_ARRAY_PGLEN;
+       phy_regarray_table_pg = RTL8723BEPHY_REG_ARRAY_PG;
+
+       if (configtype == BASEBAND_CONFIG_PHY_REG) {
+               for (i = 0; i < phy_regarray_pg_len; i = i + 6) {
+                       v1 = phy_regarray_table_pg[i];
+                       v2 = phy_regarray_table_pg[i+1];
+                       v3 = phy_regarray_table_pg[i+2];
+                       v4 = phy_regarray_table_pg[i+3];
+                       v5 = phy_regarray_table_pg[i+4];
+                       v6 = phy_regarray_table_pg[i+5];
+
+                       if (v1 < 0xcdcdcdcd) {
+                               if (phy_regarray_table_pg[i] == 0xfe ||
+                                   phy_regarray_table_pg[i] == 0xffe)
+                                       mdelay(50);
+                               else
+                                       _rtl8723be_store_tx_power_by_rate(hw,
+                                                       v1, v2, v3, v4, v5, v6);
+                               continue;
+                       } else {
+                               /*don't need the hw_body*/
+                               if (!_rtl8723be_check_condition(hw,
+                                               phy_regarray_table_pg[i])) {
+                                       i += 2; /* skip the pair of expression*/
+                                       v1 = phy_regarray_table_pg[i];
+                                       v2 = phy_regarray_table_pg[i+1];
+                                       v3 = phy_regarray_table_pg[i+2];
+                                       while (v2 != 0xDEAD) {
+                                               i += 3;
+                                               v1 = phy_regarray_table_pg[i];
+                                               v2 = phy_regarray_table_pg[i+1];
+                                               v3 = phy_regarray_table_pg[i+2];
+                                       }
+                               }
+                       }
+               }
+       } else {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "configtype != BaseBand_Config_PHY_REG\n");
+       }
+       return true;
+}
+
+bool rtl8723be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+                                            enum radio_path rfpath)
+{
+       #define READ_NEXT_RF_PAIR(v1, v2, i) \
+               do { \
+                       i += 2; \
+                       v1 = radioa_array_table[i]; \
+                       v2 = radioa_array_table[i+1]; \
+               } while (0)
+
+       int i;
+       bool rtstatus = true;
+       u32 *radioa_array_table;
+       u16 radioa_arraylen;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u32 v1 = 0, v2 = 0;
+
+       radioa_arraylen = RTL8723BE_RADIOA_1TARRAYLEN;
+       radioa_array_table = RTL8723BE_RADIOA_1TARRAY;
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "Radio_A:RTL8723BE_RADIOA_1TARRAY %d\n", radioa_arraylen);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath);
+       rtstatus = true;
+       switch (rfpath) {
+       case RF90_PATH_A:
+               for (i = 0; i < radioa_arraylen; i = i + 2) {
+                       v1 = radioa_array_table[i];
+                       v2 = radioa_array_table[i+1];
+                       if (v1 < 0xcdcdcdcd) {
+                               _rtl8723be_config_rf_radio_a(hw, v1, v2);
+                       } else { /*This line is the start line of branch.*/
+                               if (!_rtl8723be_check_condition(hw,
+                                               radioa_array_table[i])) {
+                                       /* Discard the following
+                                        * (offset, data) pairs
+                                        */
+                                       READ_NEXT_RF_PAIR(v1, v2, i);
+                                       while (v2 != 0xDEAD &&
+                                              v2 != 0xCDEF &&
+                                              v2 != 0xCDCD &&
+                                              i < radioa_arraylen - 2)
+                                               READ_NEXT_RF_PAIR(v1, v2, i);
+                                       i -= 2; /* prevent from for-loop += 2*/
+                               } else {
+                                       /* Configure matched pairs
+                                        * and skip to end of if-else.
+                                        */
+                                       READ_NEXT_RF_PAIR(v1, v2, i);
+                                       while (v2 != 0xDEAD &&
+                                              v2 != 0xCDEF &&
+                                              v2 != 0xCDCD &&
+                                              i < radioa_arraylen - 2) {
+                                               _rtl8723be_config_rf_radio_a(hw,
+                                                                       v1, v2);
+                                               READ_NEXT_RF_PAIR(v1, v2, i);
+                                       }
+
+                                       while (v2 != 0xDEAD &&
+                                              i < radioa_arraylen - 2) {
+                                               READ_NEXT_RF_PAIR(v1, v2, i);
+                                       }
+                               }
+                       }
+               }
+
+               if (rtlhal->oem_id == RT_CID_819X_HP)
+                       _rtl8723be_config_rf_radio_a(hw, 0x52, 0x7E4BD);
+
+               break;
+       case RF90_PATH_B:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       case RF90_PATH_C:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       case RF90_PATH_D:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       }
+       return true;
+}
+
+void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       rtlphy->default_initialgain[0] =
+           (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+       rtlphy->default_initialgain[1] =
+           (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+       rtlphy->default_initialgain[2] =
+           (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
+       rtlphy->default_initialgain[3] =
+           (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                "Default initial gain (c50 = 0x%x, "
+                 "c58 = 0x%x, c60 = 0x%x, c68 = 0x%x\n",
+                 rtlphy->default_initialgain[0],
+                 rtlphy->default_initialgain[1],
+                 rtlphy->default_initialgain[2],
+                 rtlphy->default_initialgain[3]);
+
+       rtlphy->framesync = (u8) rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
+                                              MASKBYTE0);
+       rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
+                                             MASKDWORD);
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                "Default framesync (0x%x) = 0x%x\n",
+                 ROFDM0_RXDETECTOR3, rtlphy->framesync);
+}
+
+void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 txpwr_level;
+       long txpwr_dbm;
+
+       txpwr_level = rtlphy->cur_cck_txpwridx;
+       txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B,
+                                                txpwr_level);
+       txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+       if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) >
+           txpwr_dbm)
+               txpwr_dbm =
+                   rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+                                                txpwr_level);
+       txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+       if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+                                        txpwr_level) > txpwr_dbm)
+               txpwr_dbm =
+                   rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+                                                txpwr_level);
+       *powerlevel = txpwr_dbm;
+}
+
+static u8 _rtl8723be_phy_get_ratesection_intxpower_byrate(enum radio_path path,
+                                                         u8 rate)
+{
+       u8 rate_section = 0;
+
+       switch (rate) {
+       case DESC92C_RATE1M:
+               rate_section = 2;
+               break;
+       case DESC92C_RATE2M:
+       case DESC92C_RATE5_5M:
+               if (path == RF90_PATH_A)
+                       rate_section = 3;
+               else if (path == RF90_PATH_B)
+                       rate_section = 2;
+               break;
+       case DESC92C_RATE11M:
+               rate_section = 3;
+               break;
+       case DESC92C_RATE6M:
+       case DESC92C_RATE9M:
+       case DESC92C_RATE12M:
+       case DESC92C_RATE18M:
+               rate_section = 0;
+               break;
+       case DESC92C_RATE24M:
+       case DESC92C_RATE36M:
+       case DESC92C_RATE48M:
+       case DESC92C_RATE54M:
+               rate_section = 1;
+               break;
+       case DESC92C_RATEMCS0:
+       case DESC92C_RATEMCS1:
+       case DESC92C_RATEMCS2:
+       case DESC92C_RATEMCS3:
+               rate_section = 4;
+               break;
+       case DESC92C_RATEMCS4:
+       case DESC92C_RATEMCS5:
+       case DESC92C_RATEMCS6:
+       case DESC92C_RATEMCS7:
+               rate_section = 5;
+               break;
+       case DESC92C_RATEMCS8:
+       case DESC92C_RATEMCS9:
+       case DESC92C_RATEMCS10:
+       case DESC92C_RATEMCS11:
+               rate_section = 6;
+               break;
+       case DESC92C_RATEMCS12:
+       case DESC92C_RATEMCS13:
+       case DESC92C_RATEMCS14:
+       case DESC92C_RATEMCS15:
+               rate_section = 7;
+               break;
+       default:
+               RT_ASSERT(true, "Rate_Section is Illegal\n");
+               break;
+       }
+       return rate_section;
+}
+
+static u8 _rtl8723be_get_txpower_by_rate(struct ieee80211_hw *hw,
+                                        enum band_type band,
+                                        enum radio_path rfpath, u8 rate)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 shift = 0, rate_section, tx_num;
+       char tx_pwr_diff = 0;
+
+       rate_section = _rtl8723be_phy_get_ratesection_intxpower_byrate(rfpath,
+                                                                      rate);
+       tx_num = RF_TX_NUM_NONIMPLEMENT;
+
+       if (tx_num == RF_TX_NUM_NONIMPLEMENT) {
+               if (rate >= DESC92C_RATEMCS8 && rate <= DESC92C_RATEMCS15)
+                       tx_num = RF_2TX;
+               else
+                       tx_num = RF_1TX;
+       }
+
+       switch (rate) {
+       case DESC92C_RATE6M:
+       case DESC92C_RATE24M:
+       case DESC92C_RATEMCS0:
+       case DESC92C_RATEMCS4:
+       case DESC92C_RATEMCS8:
+       case DESC92C_RATEMCS12:
+               shift = 0;
+               break;
+       case DESC92C_RATE1M:
+       case DESC92C_RATE2M:
+       case DESC92C_RATE9M:
+       case DESC92C_RATE36M:
+       case DESC92C_RATEMCS1:
+       case DESC92C_RATEMCS5:
+       case DESC92C_RATEMCS9:
+       case DESC92C_RATEMCS13:
+               shift = 8;
+               break;
+       case DESC92C_RATE5_5M:
+       case DESC92C_RATE12M:
+       case DESC92C_RATE48M:
+       case DESC92C_RATEMCS2:
+       case DESC92C_RATEMCS6:
+       case DESC92C_RATEMCS10:
+       case DESC92C_RATEMCS14:
+               shift = 16;
+               break;
+       case DESC92C_RATE11M:
+       case DESC92C_RATE18M:
+       case DESC92C_RATE54M:
+       case DESC92C_RATEMCS3:
+       case DESC92C_RATEMCS7:
+       case DESC92C_RATEMCS11:
+       case DESC92C_RATEMCS15:
+               shift = 24;
+               break;
+       default:
+               RT_ASSERT(true, "Rate_Section is Illegal\n");
+               break;
+       }
+       tx_pwr_diff = (u8)(rtlphy->tx_power_by_rate_offset[band][rfpath][tx_num]
+                                         [rate_section] >> shift) & 0xff;
+
+       return  tx_pwr_diff;
+}
+
+static u8 _rtl8723be_get_txpower_index(struct ieee80211_hw *hw, u8 path,
+                                      u8 rate, u8 bandwidth, u8 channel)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 index = (channel - 1);
+       u8 txpower;
+       u8 power_diff_byrate = 0;
+
+       if (channel > 14 || channel < 1) {
+               index = 0;
+               RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                        "Illegal channel!\n");
+       }
+       if (RTL8723E_RX_HAL_IS_CCK_RATE(rate))
+               txpower = rtlefuse->txpwrlevel_cck[path][index];
+       else if (DESC92C_RATE6M <= rate)
+               txpower = rtlefuse->txpwrlevel_ht40_1s[path][index];
+       else
+               RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                        "invalid rate\n");
+
+       if (DESC92C_RATE6M <= rate && rate <= DESC92C_RATE54M &&
+           !RTL8723E_RX_HAL_IS_CCK_RATE(rate))
+               txpower += rtlefuse->txpwr_legacyhtdiff[0][TX_1S];
+
+       if (bandwidth == HT_CHANNEL_WIDTH_20) {
+               if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15)
+                       txpower += rtlefuse->txpwr_ht20diff[0][TX_1S];
+               if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15)
+                       txpower += rtlefuse->txpwr_ht20diff[0][TX_2S];
+       } else if (bandwidth == HT_CHANNEL_WIDTH_20_40) {
+               if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15)
+                       txpower += rtlefuse->txpwr_ht40diff[0][TX_1S];
+               if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15)
+                       txpower += rtlefuse->txpwr_ht40diff[0][TX_2S];
+       }
+       if (rtlefuse->eeprom_regulatory != 2)
+               power_diff_byrate = _rtl8723be_get_txpower_by_rate(hw,
+                                                                  BAND_ON_2_4G,
+                                                                  path, rate);
+
+       txpower += power_diff_byrate;
+
+       if (txpower > MAX_POWER_INDEX)
+               txpower = MAX_POWER_INDEX;
+
+       return txpower;
+}
+
+static void _rtl8723be_phy_set_txpower_index(struct ieee80211_hw *hw,
+                                            u8 power_index, u8 path, u8 rate)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       if (path == RF90_PATH_A) {
+               switch (rate) {
+               case DESC92C_RATE1M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_CCK1_MCS32,
+                                              MASKBYTE1, power_index);
+                       break;
+               case DESC92C_RATE2M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11,
+                                              MASKBYTE1, power_index);
+                       break;
+               case DESC92C_RATE5_5M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11,
+                                              MASKBYTE2, power_index);
+                       break;
+               case DESC92C_RATE11M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11,
+                                              MASKBYTE3, power_index);
+                       break;
+               case DESC92C_RATE6M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
+                                              MASKBYTE0, power_index);
+                       break;
+               case DESC92C_RATE9M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
+                                              MASKBYTE1, power_index);
+                       break;
+               case DESC92C_RATE12M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
+                                              MASKBYTE2, power_index);
+                       break;
+               case DESC92C_RATE18M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
+                                              MASKBYTE3, power_index);
+                       break;
+               case DESC92C_RATE24M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
+                                              MASKBYTE0, power_index);
+                       break;
+               case DESC92C_RATE36M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
+                                              MASKBYTE1, power_index);
+                       break;
+               case DESC92C_RATE48M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
+                                              MASKBYTE2, power_index);
+                       break;
+               case DESC92C_RATE54M:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
+                                              MASKBYTE3, power_index);
+                       break;
+               case DESC92C_RATEMCS0:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
+                                              MASKBYTE0, power_index);
+                       break;
+               case DESC92C_RATEMCS1:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
+                                              MASKBYTE1, power_index);
+                       break;
+               case DESC92C_RATEMCS2:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
+                                              MASKBYTE2, power_index);
+                       break;
+               case DESC92C_RATEMCS3:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
+                                              MASKBYTE3, power_index);
+                       break;
+               case DESC92C_RATEMCS4:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
+                                              MASKBYTE0, power_index);
+                       break;
+               case DESC92C_RATEMCS5:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
+                                              MASKBYTE1, power_index);
+                       break;
+               case DESC92C_RATEMCS6:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
+                                              MASKBYTE2, power_index);
+                       break;
+               case DESC92C_RATEMCS7:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
+                                              MASKBYTE3, power_index);
+                       break;
+               case DESC92C_RATEMCS8:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
+                                              MASKBYTE0, power_index);
+                       break;
+               case DESC92C_RATEMCS9:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
+                                              MASKBYTE1, power_index);
+                       break;
+               case DESC92C_RATEMCS10:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
+                                              MASKBYTE2, power_index);
+                       break;
+               case DESC92C_RATEMCS11:
+                       rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
+                                              MASKBYTE3, power_index);
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                                "Invalid Rate!!\n");
+                       break;
+               }
+       } else {
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Invalid RFPath!!\n");
+       }
+}
+
+void rtl8723be_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 cck_rates[]  = {DESC92C_RATE1M, DESC92C_RATE2M,
+                          DESC92C_RATE5_5M, DESC92C_RATE11M};
+       u8 ofdm_rates[]  = {DESC92C_RATE6M, DESC92C_RATE9M,
+                           DESC92C_RATE12M, DESC92C_RATE18M,
+                           DESC92C_RATE24M, DESC92C_RATE36M,
+                           DESC92C_RATE48M, DESC92C_RATE54M};
+       u8 ht_rates_1t[]  = {DESC92C_RATEMCS0, DESC92C_RATEMCS1,
+                            DESC92C_RATEMCS2, DESC92C_RATEMCS3,
+                            DESC92C_RATEMCS4, DESC92C_RATEMCS5,
+                            DESC92C_RATEMCS6, DESC92C_RATEMCS7};
+       u8 i, size;
+       u8 power_index;
+
+       if (!rtlefuse->txpwr_fromeprom)
+               return;
+
+       size = sizeof(cck_rates) / sizeof(u8);
+       for (i = 0; i < size; i++) {
+               power_index = _rtl8723be_get_txpower_index(hw, RF90_PATH_A,
+                                       cck_rates[i],
+                                       rtl_priv(hw)->phy.current_chan_bw,
+                                       channel);
+               _rtl8723be_phy_set_txpower_index(hw, power_index, RF90_PATH_A,
+                                                cck_rates[i]);
+       }
+       size = sizeof(ofdm_rates) / sizeof(u8);
+       for (i = 0; i < size; i++) {
+               power_index = _rtl8723be_get_txpower_index(hw, RF90_PATH_A,
+                                       ofdm_rates[i],
+                                       rtl_priv(hw)->phy.current_chan_bw,
+                                       channel);
+               _rtl8723be_phy_set_txpower_index(hw, power_index, RF90_PATH_A,
+                                                ofdm_rates[i]);
+       }
+       size = sizeof(ht_rates_1t) / sizeof(u8);
+       for (i = 0; i < size; i++) {
+               power_index = _rtl8723be_get_txpower_index(hw, RF90_PATH_A,
+                                       ht_rates_1t[i],
+                                       rtl_priv(hw)->phy.current_chan_bw,
+                                       channel);
+               _rtl8723be_phy_set_txpower_index(hw, power_index, RF90_PATH_A,
+                                                ht_rates_1t[i]);
+       }
+}
+
+void rtl8723be_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       enum io_type iotype;
+
+       if (!is_hal_stop(rtlhal)) {
+               switch (operation) {
+               case SCAN_OPT_BACKUP:
+                       iotype = IO_CMD_PAUSE_DM_BY_SCAN;
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD,
+                                                     (u8 *)&iotype);
+                       break;
+               case SCAN_OPT_RESTORE:
+                       iotype = IO_CMD_RESUME_DM_BY_SCAN;
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD,
+                                                     (u8 *)&iotype);
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "Unknown Scan Backup operation.\n");
+                       break;
+               }
+       }
+}
+
+void rtl8723be_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u8 reg_bw_opmode;
+       u8 reg_prsr_rsc;
+
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+                "Switch to %s bandwidth\n",
+                rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+                "20MHz" : "40MHz");
+
+       if (is_hal_stop(rtlhal)) {
+               rtlphy->set_bwmode_inprogress = false;
+               return;
+       }
+
+       reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
+       reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
+
+       switch (rtlphy->current_chan_bw) {
+       case HT_CHANNEL_WIDTH_20:
+               reg_bw_opmode |= BW_OPMODE_20MHZ;
+               rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+               rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+               reg_prsr_rsc = (reg_prsr_rsc & 0x90) |
+                              (mac->cur_40_prime_sc << 5);
+               rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+               break;
+       }
+
+       switch (rtlphy->current_chan_bw) {
+       case HT_CHANNEL_WIDTH_20:
+               rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+               rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+               rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+               rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+                             (mac->cur_40_prime_sc >> 1));
+               rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+               rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
+                             (mac->cur_40_prime_sc ==
+                              HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+               break;
+       }
+       rtl8723be_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+       rtlphy->set_bwmode_inprogress = false;
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "\n");
+}
+
+void rtl8723be_phy_set_bw_mode(struct ieee80211_hw *hw,
+                           enum nl80211_channel_type ch_type)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 tmp_bw = rtlphy->current_chan_bw;
+
+       if (rtlphy->set_bwmode_inprogress)
+               return;
+       rtlphy->set_bwmode_inprogress = true;
+       if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+               rtl8723be_phy_set_bw_mode_callback(hw);
+       } else {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "false driver sleep or unload\n");
+               rtlphy->set_bwmode_inprogress = false;
+               rtlphy->current_chan_bw = tmp_bw;
+       }
+}
+
+void rtl8723be_phy_sw_chnl_callback(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u32 delay;
+
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+                "switch to channel%d\n", rtlphy->current_channel);
+       if (is_hal_stop(rtlhal))
+               return;
+       do {
+               if (!rtlphy->sw_chnl_inprogress)
+                       break;
+               if (!rtl8723be_phy_sw_chn_step_by_step(hw,
+                                                      rtlphy->current_channel,
+                                                      &rtlphy->sw_chnl_stage,
+                                                      &rtlphy->sw_chnl_step,
+                                                      &delay)) {
+                       if (delay > 0)
+                               mdelay(delay);
+                       else
+                               continue;
+               } else {
+                       rtlphy->sw_chnl_inprogress = false;
+               }
+               break;
+       } while (true);
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
+}
+
+u8 rtl8723be_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       if (rtlphy->sw_chnl_inprogress)
+               return 0;
+       if (rtlphy->set_bwmode_inprogress)
+               return 0;
+       RT_ASSERT((rtlphy->current_channel <= 14),
+                 "WIRELESS_MODE_G but channel>14");
+       rtlphy->sw_chnl_inprogress = true;
+       rtlphy->sw_chnl_stage = 0;
+       rtlphy->sw_chnl_step = 0;
+       if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+               rtl8723be_phy_sw_chnl_callback(hw);
+               RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+                        "sw_chnl_inprogress false schdule "
+                         "workitem current channel %d\n",
+                         rtlphy->current_channel);
+               rtlphy->sw_chnl_inprogress = false;
+       } else {
+               RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+                        "sw_chnl_inprogress false driver sleep or"
+                         " unload\n");
+               rtlphy->sw_chnl_inprogress = false;
+       }
+       return 1;
+}
+
+static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw,
+                                             u8 channel, u8 *stage,
+                                             u8 *step, u32 *delay)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+       u32 precommoncmdcnt;
+       struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+       u32 postcommoncmdcnt;
+       struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+       u32 rfdependcmdcnt;
+       struct swchnlcmd *currentcmd = NULL;
+       u8 rfpath;
+       u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+       precommoncmdcnt = 0;
+       rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+                                        MAX_PRECMD_CNT,
+                                        CMDID_SET_TXPOWEROWER_LEVEL,
+                                        0, 0, 0);
+       rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+                                        MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+       postcommoncmdcnt = 0;
+       rtl8723_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+                                        MAX_POSTCMD_CNT, CMDID_END,
+                                        0, 0, 0);
+       rfdependcmdcnt = 0;
+
+       RT_ASSERT((channel >= 1 && channel <= 14),
+                 "illegal channel for Zebra: %d\n", channel);
+
+       rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+                                        MAX_RFDEPENDCMD_CNT,
+                                        CMDID_RF_WRITEREG,
+                                        RF_CHNLBW, channel, 10);
+
+       rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+                                        MAX_RFDEPENDCMD_CNT,
+                                        CMDID_END, 0, 0, 0);
+
+       do {
+               switch (*stage) {
+               case 0:
+                       currentcmd = &precommoncmd[*step];
+                       break;
+               case 1:
+                       currentcmd = &rfdependcmd[*step];
+                       break;
+               case 2:
+                       currentcmd = &postcommoncmd[*step];
+                       break;
+               }
+
+               if (currentcmd->cmdid == CMDID_END) {
+                       if ((*stage) == 2) {
+                               return true;
+                       } else {
+                               (*stage)++;
+                               (*step) = 0;
+                               continue;
+                       }
+               }
+
+               switch (currentcmd->cmdid) {
+               case CMDID_SET_TXPOWEROWER_LEVEL:
+                       rtl8723be_phy_set_txpower_level(hw, channel);
+                       break;
+               case CMDID_WRITEPORT_ULONG:
+                       rtl_write_dword(rtlpriv, currentcmd->para1,
+                                       currentcmd->para2);
+                       break;
+               case CMDID_WRITEPORT_USHORT:
+                       rtl_write_word(rtlpriv, currentcmd->para1,
+                                      (u16) currentcmd->para2);
+                       break;
+               case CMDID_WRITEPORT_UCHAR:
+                       rtl_write_byte(rtlpriv, currentcmd->para1,
+                                      (u8) currentcmd->para2);
+                       break;
+               case CMDID_RF_WRITEREG:
+                       for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+                               rtlphy->rfreg_chnlval[rfpath] =
+                                   ((rtlphy->rfreg_chnlval[rfpath] &
+                                     0xfffffc00) | currentcmd->para2);
+
+                               rtl_set_rfreg(hw, (enum radio_path)rfpath,
+                                             currentcmd->para1,
+                                             RFREG_OFFSET_MASK,
+                                             rtlphy->rfreg_chnlval[rfpath]);
+                       }
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not process\n");
+                       break;
+               }
+
+               break;
+       } while (true);
+
+       (*delay) = currentcmd->msdelay;
+       (*step)++;
+       return false;
+}
+
+static u8 _rtl8723be_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+       u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
+       u8 result = 0x00;
+
+       rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1c);
+       rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x30008c1c);
+       rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x8214032a);
+       rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160000);
+
+       rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
+       rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+       rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
+
+       mdelay(IQK_DELAY_TIME);
+
+       reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+       reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
+       reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
+       reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
+
+       if (!(reg_eac & BIT(28)) &&
+           (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+           (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+               result |= 0x01;
+       return result;
+}
+
+static bool phy_similarity_cmp(struct ieee80211_hw *hw, long result[][8],
+                              u8 c1, u8 c2)
+{
+       u32 i, j, diff, simularity_bitmap, bound;
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       u8 final_candidate[2] = { 0xFF, 0xFF };
+       bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version);
+
+       if (is2t)
+               bound = 8;
+       else
+               bound = 4;
+
+       simularity_bitmap = 0;
+
+       for (i = 0; i < bound; i++) {
+               diff = (result[c1][i] > result[c2][i]) ?
+                   (result[c1][i] - result[c2][i]) :
+                   (result[c2][i] - result[c1][i]);
+
+               if (diff > MAX_TOLERANCE) {
+                       if ((i == 2 || i == 6) && !simularity_bitmap) {
+                               if (result[c1][i] + result[c1][i + 1] == 0)
+                                       final_candidate[(i / 4)] = c2;
+                               else if (result[c2][i] + result[c2][i + 1] == 0)
+                                       final_candidate[(i / 4)] = c1;
+                               else
+                                       simularity_bitmap |= (1 << i);
+                       } else {
+                               simularity_bitmap |= (1 << i);
+                       }
+               }
+       }
+
+       if (simularity_bitmap == 0) {
+               for (i = 0; i < (bound / 4); i++) {
+                       if (final_candidate[i] != 0xFF) {
+                               for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+                                       result[3][j] =
+                                               result[final_candidate[i]][j];
+                               bresult = false;
+                       }
+               }
+               return bresult;
+       } else if (!(simularity_bitmap & 0x0F)) {
+               for (i = 0; i < 4; i++)
+                       result[3][i] = result[c1][i];
+               return false;
+       } else if (!(simularity_bitmap & 0xF0) && is2t) {
+               for (i = 4; i < 8; i++)
+                       result[3][i] = result[c1][i];
+               return false;
+       } else {
+               return false;
+       }
+}
+
+static void _rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw,
+                                       long result[][8], u8 t, bool is2t)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u32 i;
+       u8 patha_ok;
+       u32 adda_reg[IQK_ADDA_REG_NUM] = {
+               0x85c, 0xe6c, 0xe70, 0xe74,
+               0xe78, 0xe7c, 0xe80, 0xe84,
+               0xe88, 0xe8c, 0xed0, 0xed4,
+               0xed8, 0xedc, 0xee0, 0xeec
+       };
+
+       u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
+               0x522, 0x550, 0x551, 0x040
+       };
+       u32 iqk_bb_reg[IQK_BB_REG_NUM] = {
+               ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR,
+               RFPGA0_XCD_RFINTERFACESW, 0xb68, 0xb6c,
+               0x870, 0x860,
+               0x864, 0x800
+       };
+       const u32 retrycount = 2;
+       u32 path_sel_bb, path_sel_rf;
+       u8 tmp_reg_c50, tmp_reg_c58;
+
+       tmp_reg_c50 = rtl_get_bbreg(hw, 0xc50, MASKBYTE0);
+       tmp_reg_c58 = rtl_get_bbreg(hw, 0xc58, MASKBYTE0);
+
+       if (t == 0) {
+               rtl8723_save_adda_registers(hw, adda_reg,
+                                           rtlphy->adda_backup, 16);
+               rtl8723_phy_save_mac_registers(hw, iqk_mac_reg,
+                                              rtlphy->iqk_mac_backup);
+               rtl8723_save_adda_registers(hw, iqk_bb_reg,
+                                           rtlphy->iqk_bb_backup,
+                                           IQK_BB_REG_NUM);
+       }
+       rtl8723_phy_path_adda_on(hw, adda_reg, true, is2t);
+       if (t == 0) {
+               rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
+                                               RFPGA0_XA_HSSIPARAMETER1,
+                                               BIT(8));
+       }
+       if (!rtlphy->rfpi_enable)
+               rtl8723_phy_pi_mode_switch(hw, true);
+
+       path_sel_bb = rtl_get_bbreg(hw, 0x948, MASKDWORD);
+       path_sel_rf = rtl_get_rfreg(hw, RF90_PATH_A, 0xb0, 0xfffff);
+
+       /*BB Setting*/
+       rtl_set_bbreg(hw, 0x800, BIT(24), 0x00);
+       rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
+       rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
+       rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
+
+       rtl_set_bbreg(hw, 0x870, BIT(10), 0x01);
+       rtl_set_bbreg(hw, 0x870, BIT(26), 0x01);
+       rtl_set_bbreg(hw, 0x860, BIT(10), 0x00);
+       rtl_set_bbreg(hw, 0x864, BIT(10), 0x00);
+
+       if (is2t)
+               rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASKDWORD, 0x10000);
+       rtl8723_phy_mac_setting_calibration(hw, iqk_mac_reg,
+                                           rtlphy->iqk_mac_backup);
+       rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000);
+
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+       rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
+       rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x81004800);
+       for (i = 0; i < retrycount; i++) {
+               patha_ok = _rtl8723be_phy_path_a_iqk(hw, is2t);
+               if (patha_ok == 0x01) {
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                "Path A Tx IQK Success!!\n");
+                       result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
+                                       0x3FF0000) >> 16;
+                       result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
+                                       0x3FF0000) >> 16;
+                       break;
+               }
+       }
+
+       if (0 == patha_ok)
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "Path A IQK Success!!\n");
+       if (is2t) {
+               rtl8723_phy_path_a_standby(hw);
+               rtl8723_phy_path_adda_on(hw, adda_reg, false, is2t);
+       }
+
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
+
+       if (t != 0) {
+               if (!rtlphy->rfpi_enable)
+                       rtl8723_phy_pi_mode_switch(hw, false);
+               rtl8723_phy_reload_adda_registers(hw, adda_reg,
+                                                 rtlphy->adda_backup, 16);
+               rtl8723_phy_reload_mac_registers(hw, iqk_mac_reg,
+                                                rtlphy->iqk_mac_backup);
+               rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg,
+                                                 rtlphy->iqk_bb_backup,
+                                                 IQK_BB_REG_NUM);
+
+               rtl_set_bbreg(hw, 0x948, MASKDWORD, path_sel_bb);
+               rtl_set_rfreg(hw, RF90_PATH_B, 0xb0, 0xfffff, path_sel_rf);
+
+               rtl_set_bbreg(hw, 0xc50, MASKBYTE0, 0x50);
+               rtl_set_bbreg(hw, 0xc50, MASKBYTE0, tmp_reg_c50);
+               if (is2t) {
+                       rtl_set_bbreg(hw, 0xc58, MASKBYTE0, 0x50);
+                       rtl_set_bbreg(hw, 0xc58, MASKBYTE0, tmp_reg_c58);
+               }
+               rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00);
+               rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00);
+       }
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "8723be IQK Finish!!\n");
+}
+
+static void _rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmpreg;
+       u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+
+       tmpreg = rtl_read_byte(rtlpriv, 0xd03);
+
+       if ((tmpreg & 0x70) != 0)
+               rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F);
+       else
+               rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+
+       if ((tmpreg & 0x70) != 0) {
+               rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS);
+
+               if (is2t)
+                       rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00,
+                                                 MASK12BITS);
+
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS,
+                             (rf_a_mode & 0x8FFFF) | 0x10000);
+
+               if (is2t)
+                       rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
+                                     (rf_b_mode & 0x8FFFF) | 0x10000);
+       }
+       lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS);
+
+       rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdfbe0);
+       rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, 0x8c0a);
+
+       mdelay(100);
+
+       rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdffe0);
+
+       if ((tmpreg & 0x70) != 0) {
+               rtl_write_byte(rtlpriv, 0xd03, tmpreg);
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode);
+
+               if (is2t)
+                       rtl_set_rfreg(hw, RF90_PATH_B, 0x00,
+                                     MASK12BITS, rf_b_mode);
+       } else {
+               rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+       }
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+}
+
+static void _rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw,
+                                            bool bmain, bool is2t)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+
+       if (is_hal_stop(rtlhal)) {
+               u8 u1btmp;
+               u1btmp = rtl_read_byte(rtlpriv, REG_LEDCFG0);
+               rtl_write_byte(rtlpriv, REG_LEDCFG0, u1btmp | BIT(7));
+               rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
+       }
+       if (is2t) {
+               if (bmain)
+                       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+                                     BIT(5) | BIT(6), 0x1);
+               else
+                       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+                                     BIT(5) | BIT(6), 0x2);
+       } else {
+               rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(8) | BIT(9), 0);
+               rtl_set_bbreg(hw, 0x914, MASKLWORD, 0x0201);
+
+               /* We use the RF definition of MAIN and AUX,
+                * left antenna and right antenna repectively.
+                * Default output at AUX.
+                */
+               if (bmain) {
+                       rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
+                                     BIT(14) | BIT(13) | BIT(12), 0);
+                       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+                                     BIT(5) | BIT(4) | BIT(3), 0);
+                       if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+                               rtl_set_bbreg(hw, CONFIG_RAM64X16, BIT(31), 0);
+               } else {
+                       rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
+                                     BIT(14) | BIT(13) | BIT(12), 1);
+                       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+                                     BIT(5) | BIT(4) | BIT(3), 1);
+                       if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+                               rtl_set_bbreg(hw, CONFIG_RAM64X16, BIT(31), 1);
+               }
+       }
+}
+
+#undef IQK_ADDA_REG_NUM
+#undef IQK_DELAY_TIME
+
+void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       long result[4][8];
+       u8 i, final_candidate;
+       bool patha_ok, pathb_ok;
+       long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
+           reg_ecc, reg_tmp = 0;
+       bool is12simular, is13simular, is23simular;
+       u32 iqk_bb_reg[9] = {
+               ROFDM0_XARXIQIMBALANCE,
+               ROFDM0_XBRXIQIMBALANCE,
+               ROFDM0_ECCATHRESHOLD,
+               ROFDM0_AGCRSSITABLE,
+               ROFDM0_XATXIQIMBALANCE,
+               ROFDM0_XBTXIQIMBALANCE,
+               ROFDM0_XCTXAFE,
+               ROFDM0_XDTXAFE,
+               ROFDM0_RXIQEXTANTA
+       };
+
+       if (recovery) {
+               rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg,
+                                                 rtlphy->iqk_bb_backup, 9);
+               return;
+       }
+
+       for (i = 0; i < 8; i++) {
+               result[0][i] = 0;
+               result[1][i] = 0;
+               result[2][i] = 0;
+               result[3][i] = 0;
+       }
+       final_candidate = 0xff;
+       patha_ok = false;
+       pathb_ok = false;
+       is12simular = false;
+       is23simular = false;
+       is13simular = false;
+       for (i = 0; i < 3; i++) {
+               if (get_rf_type(rtlphy) == RF_2T2R)
+                       _rtl8723be_phy_iq_calibrate(hw, result, i, true);
+               else
+                       _rtl8723be_phy_iq_calibrate(hw, result, i, false);
+               if (i == 1) {
+                       is12simular = phy_similarity_cmp(hw, result, 0, 1);
+                       if (is12simular) {
+                               final_candidate = 0;
+                               break;
+                       }
+               }
+               if (i == 2) {
+                       is13simular = phy_similarity_cmp(hw, result, 0, 2);
+                       if (is13simular) {
+                               final_candidate = 0;
+                               break;
+                       }
+                       is23simular = phy_similarity_cmp(hw, result, 1, 2);
+                       if (is23simular) {
+                               final_candidate = 1;
+                       } else {
+                               for (i = 0; i < 8; i++)
+                                       reg_tmp += result[3][i];
+
+                               if (reg_tmp != 0)
+                                       final_candidate = 3;
+                               else
+                                       final_candidate = 0xFF;
+                       }
+               }
+       }
+       for (i = 0; i < 4; i++) {
+               reg_e94 = result[i][0];
+               reg_e9c = result[i][1];
+               reg_ea4 = result[i][2];
+               reg_eac = result[i][3];
+               reg_eb4 = result[i][4];
+               reg_ebc = result[i][5];
+               reg_ec4 = result[i][6];
+               reg_ecc = result[i][7];
+       }
+       if (final_candidate != 0xff) {
+               reg_e94 = result[final_candidate][0];
+               rtlphy->reg_e94 = reg_e94;
+               reg_e9c = result[final_candidate][1];
+               rtlphy->reg_e9c = reg_e9c;
+               reg_ea4 = result[final_candidate][2];
+               reg_eac = result[final_candidate][3];
+               reg_eb4 = result[final_candidate][4];
+               rtlphy->reg_eb4 = reg_eb4;
+               reg_ebc = result[final_candidate][5];
+               rtlphy->reg_ebc = reg_ebc;
+               reg_ec4 = result[final_candidate][6];
+               reg_ecc = result[final_candidate][7];
+               patha_ok = true;
+               pathb_ok = true;
+       } else {
+               rtlphy->reg_e94 = 0x100;
+               rtlphy->reg_eb4 = 0x100;
+               rtlphy->reg_e9c = 0x0;
+               rtlphy->reg_ebc = 0x0;
+       }
+       if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
+               rtl8723_phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
+                                                  final_candidate,
+                                                  (reg_ea4 == 0));
+       if (final_candidate != 0xFF) {
+               for (i = 0; i < IQK_MATRIX_REG_NUM; i++)
+                       rtlphy->iqk_matrix[0].value[0][i] =
+                                               result[final_candidate][i];
+               rtlphy->iqk_matrix[0].iqk_done = true;
+       }
+       rtl8723_save_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9);
+}
+
+void rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
+       u32 timeout = 2000, timecount = 0;
+
+       while (rtlpriv->mac80211.act_scanning && timecount < timeout) {
+               udelay(50);
+               timecount += 50;
+       }
+
+       rtlphy->lck_inprogress = true;
+       RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+               "LCK:Start!!! currentband %x delay %d ms\n",
+               rtlhal->current_bandtype, timecount);
+
+       _rtl8723be_phy_lc_calibrate(hw, false);
+
+       rtlphy->lck_inprogress = false;
+}
+
+void rtl23b_phy_ap_calibrate(struct ieee80211_hw *hw, char delta)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       if (rtlphy->apk_done)
+               return;
+
+       return;
+}
+
+void rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
+{
+       _rtl8723be_phy_set_rfpath_switch(hw, bmain, false);
+}
+
+static void rtl8723be_phy_set_io(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                "--->Cmd(%#x), set_io_inprogress(%d)\n",
+                 rtlphy->current_io_type, rtlphy->set_io_inprogress);
+       switch (rtlphy->current_io_type) {
+       case IO_CMD_RESUME_DM_BY_SCAN:
+               rtlpriv->dm_digtable.cur_igvalue =
+                                rtlphy->initgain_backup.xaagccore1;
+               /*rtl92c_dm_write_dig(hw);*/
+               rtl8723be_phy_set_txpower_level(hw, rtlphy->current_channel);
+               rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x83);
+               break;
+       case IO_CMD_PAUSE_DM_BY_SCAN:
+               rtlphy->initgain_backup.xaagccore1 =
+                                rtlpriv->dm_digtable.cur_igvalue;
+               rtlpriv->dm_digtable.cur_igvalue = 0x17;
+               rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x40);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       }
+       rtlphy->set_io_inprogress = false;
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                "(%#x)\n", rtlphy->current_io_type);
+}
+
+bool rtl8723be_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       bool postprocessing = false;
+
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
+                 iotype, rtlphy->set_io_inprogress);
+       do {
+               switch (iotype) {
+               case IO_CMD_RESUME_DM_BY_SCAN:
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                                "[IO CMD] Resume DM after scan.\n");
+                       postprocessing = true;
+                       break;
+               case IO_CMD_PAUSE_DM_BY_SCAN:
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                                "[IO CMD] Pause DM before scan.\n");
+                       postprocessing = true;
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not process\n");
+                       break;
+               }
+       } while (false);
+       if (postprocessing && !rtlphy->set_io_inprogress) {
+               rtlphy->set_io_inprogress = true;
+               rtlphy->current_io_type = iotype;
+       } else {
+               return false;
+       }
+       rtl8723be_phy_set_io(hw);
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype);
+       return true;
+}
+
+static void rtl8723be_phy_set_rf_on(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+       rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+}
+
+static void _rtl8723be_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+       rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+       rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
+}
+
+static bool _rtl8723be_phy_set_rf_power_state(struct ieee80211_hw *hw,
+                                             enum rf_pwrstate rfpwr_state)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       bool bresult = true;
+       u8 i, queue_id;
+       struct rtl8192_tx_ring *ring = NULL;
+
+       switch (rfpwr_state) {
+       case ERFON:
+               if ((ppsc->rfpwr_state == ERFOFF) &&
+                   RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+                       bool rtstatus;
+                       u32 initialize_count = 0;
+                       do {
+                               initialize_count++;
+                               RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                                        "IPS Set eRf nic enable\n");
+                               rtstatus = rtl_ps_enable_nic(hw);
+                       } while (!rtstatus && (initialize_count < 10));
+                               RT_CLEAR_PS_LEVEL(ppsc,
+                                                 RT_RF_OFF_LEVL_HALT_NIC);
+               } else {
+                       RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                                "Set ERFON sleeped:%d ms\n",
+                                 jiffies_to_msecs(jiffies -
+                                                  ppsc->last_sleep_jiffies));
+                       ppsc->last_awake_jiffies = jiffies;
+                       rtl8723be_phy_set_rf_on(hw);
+               }
+               if (mac->link_state == MAC80211_LINKED)
+                       rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK);
+               else
+                       rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK);
+               break;
+       case ERFOFF:
+               for (queue_id = 0, i = 0;
+                    queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+                       ring = &pcipriv->dev.tx_ring[queue_id];
+                       if (skb_queue_len(&ring->queue) == 0) {
+                               queue_id++;
+                               continue;
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                        "eRf Off/Sleep: %d times "
+                                         "TcbBusyQueue[%d] =%d before "
+                                         "doze!\n", (i + 1), queue_id,
+                                         skb_queue_len(&ring->queue));
+
+                               udelay(10);
+                               i++;
+                       }
+                       if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                        "\n ERFSLEEP: %d times "
+                                         "TcbBusyQueue[%d] = %d !\n",
+                                         MAX_DOZE_WAITING_TIMES_9x,
+                                         queue_id,
+                                         skb_queue_len(&ring->queue));
+                               break;
+                       }
+               }
+
+               if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+                       RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                                "IPS Set eRf nic disable\n");
+                       rtl_ps_disable_nic(hw);
+                       RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+               } else {
+                       if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
+                               rtlpriv->cfg->ops->led_control(hw,
+                                                              LED_CTL_NO_LINK);
+                       } else {
+                               rtlpriv->cfg->ops->led_control(hw,
+                                                            LED_CTL_POWER_OFF);
+                       }
+               }
+               break;
+       case ERFSLEEP:
+               if (ppsc->rfpwr_state == ERFOFF)
+                       break;
+               for (queue_id = 0, i = 0;
+                    queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+                       ring = &pcipriv->dev.tx_ring[queue_id];
+                       if (skb_queue_len(&ring->queue) == 0) {
+                               queue_id++;
+                               continue;
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                        "eRf Off/Sleep: %d times "
+                                         "TcbBusyQueue[%d] =%d before "
+                                         "doze!\n", (i + 1), queue_id,
+                                         skb_queue_len(&ring->queue));
+
+                               udelay(10);
+                               i++;
+                       }
+                       if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                        "\n ERFSLEEP: %d times "
+                                         "TcbBusyQueue[%d] = %d !\n",
+                                         MAX_DOZE_WAITING_TIMES_9x,
+                                         queue_id,
+                                         skb_queue_len(&ring->queue));
+                               break;
+                       }
+               }
+               RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                        "Set ERFSLEEP awaked:%d ms\n",
+                         jiffies_to_msecs(jiffies -
+                                          ppsc->last_awake_jiffies));
+               ppsc->last_sleep_jiffies = jiffies;
+               _rtl8723be_phy_set_rf_sleep(hw);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               bresult = false;
+               break;
+       }
+       if (bresult)
+               ppsc->rfpwr_state = rfpwr_state;
+       return bresult;
+}
+
+bool rtl8723be_phy_set_rf_power_state(struct ieee80211_hw *hw,
+                                     enum rf_pwrstate rfpwr_state)
+{
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       bool bresult = false;
+
+       if (rfpwr_state == ppsc->rfpwr_state)
+               return bresult;
+       bresult = _rtl8723be_phy_set_rf_power_state(hw, rfpwr_state);
+       return bresult;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h
new file mode 100644 (file)
index 0000000..444ef95
--- /dev/null
@@ -0,0 +1,217 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_PHY_H__
+#define __RTL8723BE_PHY_H__
+
+/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/
+#define MAX_TX_COUNT           4
+#define        TX_1S                   0
+#define        TX_2S                   1
+
+#define        MAX_POWER_INDEX         0x3F
+
+#define MAX_PRECMD_CNT                 16
+#define MAX_RFDEPENDCMD_CNT            16
+#define MAX_POSTCMD_CNT                16
+
+#define MAX_DOZE_WAITING_TIMES_9x      64
+
+#define RT_CANNOT_IO(hw)               false
+#define HIGHPOWER_RADIOA_ARRAYLEN      22
+
+#define IQK_ADDA_REG_NUM               16
+#define IQK_BB_REG_NUM                 9
+#define MAX_TOLERANCE                  5
+#define        IQK_DELAY_TIME                  10
+#define        index_mapping_NUM               15
+
+#define        APK_BB_REG_NUM                  5
+#define        APK_AFE_REG_NUM                 16
+#define        APK_CURVE_REG_NUM               4
+#define        PATH_NUM                        1
+
+#define LOOP_LIMIT                     5
+#define MAX_STALL_TIME                 50
+#define ANTENNADIVERSITYVALUE          0x80
+#define MAX_TXPWR_IDX_NMODE_92S                63
+#define RESET_CNT_LIMIT                        3
+
+#define IQK_ADDA_REG_NUM               16
+#define IQK_MAC_REG_NUM                        4
+
+#define RF6052_MAX_PATH                        2
+
+#define CT_OFFSET_MAC_ADDR             0X16
+
+#define CT_OFFSET_CCK_TX_PWR_IDX               0x5A
+#define CT_OFFSET_HT401S_TX_PWR_IDX            0x60
+#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF       0x66
+#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF         0x69
+#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF         0x6C
+
+#define CT_OFFSET_HT40_MAX_PWR_OFFSET          0x6F
+#define CT_OFFSET_HT20_MAX_PWR_OFFSET          0x72
+
+#define CT_OFFSET_CHANNEL_PLAH                 0x75
+#define CT_OFFSET_THERMAL_METER                        0x78
+#define CT_OFFSET_RF_OPTION                    0x79
+#define CT_OFFSET_VERSION                      0x7E
+#define CT_OFFSET_CUSTOMER_ID                  0x7F
+
+#define RTL92C_MAX_PATH_NUM                    2
+
+enum hw90_block_e {
+       HW90_BLOCK_MAC = 0,
+       HW90_BLOCK_PHY0 = 1,
+       HW90_BLOCK_PHY1 = 2,
+       HW90_BLOCK_RF = 3,
+       HW90_BLOCK_MAXIMUM = 4,
+};
+
+enum baseband_config_type {
+       BASEBAND_CONFIG_PHY_REG = 0,
+       BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+enum ra_offset_area {
+       RA_OFFSET_LEGACY_OFDM1,
+       RA_OFFSET_LEGACY_OFDM2,
+       RA_OFFSET_HT_OFDM1,
+       RA_OFFSET_HT_OFDM2,
+       RA_OFFSET_HT_OFDM3,
+       RA_OFFSET_HT_OFDM4,
+       RA_OFFSET_HT_CCK,
+};
+
+enum antenna_path {
+       ANTENNA_NONE,
+       ANTENNA_D,
+       ANTENNA_C,
+       ANTENNA_CD,
+       ANTENNA_B,
+       ANTENNA_BD,
+       ANTENNA_BC,
+       ANTENNA_BCD,
+       ANTENNA_A,
+       ANTENNA_AD,
+       ANTENNA_AC,
+       ANTENNA_ACD,
+       ANTENNA_AB,
+       ANTENNA_ABD,
+       ANTENNA_ABC,
+       ANTENNA_ABCD
+};
+
+struct r_antenna_select_ofdm {
+       u32 r_tx_antenna:4;
+       u32 r_ant_l:4;
+       u32 r_ant_non_ht:4;
+       u32 r_ant_ht1:4;
+       u32 r_ant_ht2:4;
+       u32 r_ant_ht_s1:4;
+       u32 r_ant_non_ht_s1:4;
+       u32 ofdm_txsc:2;
+       u32 reserved:2;
+};
+
+struct r_antenna_select_cck {
+       u8 r_cckrx_enable_2:2;
+       u8 r_cckrx_enable:2;
+       u8 r_ccktx_enable:4;
+};
+
+
+struct efuse_contents {
+       u8 mac_addr[ETH_ALEN];
+       u8 cck_tx_power_idx[6];
+       u8 ht40_1s_tx_power_idx[6];
+       u8 ht40_2s_tx_power_idx_diff[3];
+       u8 ht20_tx_power_idx_diff[3];
+       u8 ofdm_tx_power_idx_diff[3];
+       u8 ht40_max_power_offset[3];
+       u8 ht20_max_power_offset[3];
+       u8 channel_plan;
+       u8 thermal_meter;
+       u8 rf_option[5];
+       u8 version;
+       u8 oem_id;
+       u8 regulatory;
+};
+
+struct tx_power_struct {
+       u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 legacy_ht_txpowerdiff;
+       u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 pwrgroup_cnt;
+       u32 mcs_original_offset[4][16];
+};
+
+enum _ANT_DIV_TYPE {
+       NO_ANTDIV                               = 0xFF,
+       CG_TRX_HW_ANTDIV                = 0x01,
+       CGCS_RX_HW_ANTDIV               = 0x02,
+       FIXED_HW_ANTDIV         = 0x03,
+       CG_TRX_SMART_ANTDIV             = 0x04,
+       CGCS_RX_SW_ANTDIV               = 0x05,
+};
+
+u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw,
+                              enum radio_path rfpath,
+                              u32 regaddr, u32 bitmask);
+void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw,
+                             enum radio_path rfpath,
+                             u32 regaddr, u32 bitmask, u32 data);
+bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw);
+bool rtl8723be_phy_bb_config(struct ieee80211_hw *hw);
+bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw);
+void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw,
+                                    long *powerlevel);
+void rtl8723be_phy_set_txpower_level(struct ieee80211_hw *hw,
+                                    u8 channel);
+void rtl8723be_phy_scan_operation_backup(struct ieee80211_hw *hw,
+                                        u8 operation);
+void rtl8723be_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+void rtl8723be_phy_set_bw_mode(struct ieee80211_hw *hw,
+                              enum nl80211_channel_type ch_type);
+void rtl8723be_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+u8 rtl8723be_phy_sw_chnl(struct ieee80211_hw *hw);
+void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw,
+                               bool b_recovery);
+void rtl23b_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
+void rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw);
+void rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
+bool rtl8723be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+                                            enum radio_path rfpath);
+bool rtl8723be_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+bool rtl8723be_phy_set_rf_power_state(struct ieee80211_hw *hw,
+                                     enum rf_pwrstate rfpwr_state);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c
new file mode 100644 (file)
index 0000000..b5167e7
--- /dev/null
@@ -0,0 +1,106 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseqcmd.h"
+#include "pwrseq.h"
+
+
+/* drivers should parse below arrays and do the corresponding actions */
+/*3 Power on  Array*/
+struct wlan_pwr_cfg rtl8723B_power_on_flow[RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS +
+                                          RTL8723B_TRANS_END_STEPS] = {
+       RTL8723B_TRANS_CARDEMU_TO_ACT
+       RTL8723B_TRANS_END
+};
+
+/*3Radio off GPIO Array */
+struct wlan_pwr_cfg rtl8723B_radio_off_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS
+                                           + RTL8723B_TRANS_END_STEPS] = {
+       RTL8723B_TRANS_ACT_TO_CARDEMU
+       RTL8723B_TRANS_END
+};
+
+/*3Card Disable Array*/
+struct wlan_pwr_cfg rtl8723B_card_disable_flow
+                               [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+                                RTL8723B_TRANS_END_STEPS] = {
+       RTL8723B_TRANS_ACT_TO_CARDEMU
+       RTL8723B_TRANS_CARDEMU_TO_CARDDIS
+       RTL8723B_TRANS_END
+};
+
+/*3 Card Enable Array*/
+struct wlan_pwr_cfg rtl8723B_card_enable_flow
+                               [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+                                RTL8723B_TRANS_END_STEPS] = {
+       RTL8723B_TRANS_CARDDIS_TO_CARDEMU
+       RTL8723B_TRANS_CARDEMU_TO_ACT
+       RTL8723B_TRANS_END
+};
+
+/*3Suspend Array*/
+struct wlan_pwr_cfg rtl8723B_suspend_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                         RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS +
+                                         RTL8723B_TRANS_END_STEPS] = {
+       RTL8723B_TRANS_ACT_TO_CARDEMU
+       RTL8723B_TRANS_CARDEMU_TO_SUS
+       RTL8723B_TRANS_END
+};
+
+/*3 Resume Array*/
+struct wlan_pwr_cfg rtl8723B_resume_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                        RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS +
+                                        RTL8723B_TRANS_END_STEPS] = {
+       RTL8723B_TRANS_SUS_TO_CARDEMU
+       RTL8723B_TRANS_CARDEMU_TO_ACT
+       RTL8723B_TRANS_END
+};
+
+/*3HWPDN Array*/
+struct wlan_pwr_cfg rtl8723B_hwpdn_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                       RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+                                       RTL8723B_TRANS_END_STEPS] = {
+       RTL8723B_TRANS_ACT_TO_CARDEMU
+       RTL8723B_TRANS_CARDEMU_TO_PDN
+       RTL8723B_TRANS_END
+};
+
+/*3 Enter LPS */
+struct wlan_pwr_cfg rtl8723B_enter_lps_flow[RTL8723B_TRANS_ACT_TO_LPS_STEPS +
+                                           RTL8723B_TRANS_END_STEPS] = {
+       /*FW behavior*/
+       RTL8723B_TRANS_ACT_TO_LPS
+       RTL8723B_TRANS_END
+};
+
+/*3 Leave LPS */
+struct wlan_pwr_cfg rtl8723B_leave_lps_flow[RTL8723B_TRANS_LPS_TO_ACT_STEPS +
+                                           RTL8723B_TRANS_END_STEPS] = {
+       /*FW behavior*/
+       RTL8723B_TRANS_LPS_TO_ACT
+       RTL8723B_TRANS_END
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h
new file mode 100644 (file)
index 0000000..a62f43e
--- /dev/null
@@ -0,0 +1,304 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_PWRSEQ_H__
+#define __RTL8723BE_PWRSEQ_H__
+
+/*     Check document WM-20130425-JackieLau-RTL8723B_Power_Architecture v05.vsd
+ *     There are 6 HW Power States:
+ *     0: POFF--Power Off
+ *     1: PDN--Power Down
+ *     2: CARDEMU--Card Emulation
+ *     3: ACT--Active Mode
+ *     4: LPS--Low Power State
+ *     5: SUS--Suspend
+ *
+ *     The transition from different states are defined below
+ *     TRANS_CARDEMU_TO_ACT
+ *     TRANS_ACT_TO_CARDEMU
+ *     TRANS_CARDEMU_TO_SUS
+ *     TRANS_SUS_TO_CARDEMU
+ *     TRANS_CARDEMU_TO_PDN
+ *     TRANS_ACT_TO_LPS
+ *     TRANS_LPS_TO_ACT
+ *
+ *     TRANS_END
+ */
+#define        RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS     23
+#define        RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS     15
+#define        RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS     15
+#define        RTL8723B_TRANS_SUS_TO_CARDEMU_STEPS     15
+#define        RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS     15
+#define        RTL8723B_TRANS_PDN_TO_CARDEMU_STEPS     15
+#define        RTL8723B_TRANS_ACT_TO_LPS_STEPS         15
+#define        RTL8723B_TRANS_LPS_TO_ACT_STEPS         15
+#define        RTL8723B_TRANS_END_STEPS                1
+
+#define RTL8723B_TRANS_CARDEMU_TO_ACT                                  \
+       {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+        PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,                          \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},              \
+       {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+        PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,                          \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},                   \
+       {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+        PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,                          \
+        PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},          \
+       {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+        PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,                          \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), 0},                   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)|BIT(2)), 0},   \
+       {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0) , 0},                  \
+       {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},            \
+       {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0) , BIT(0)},             \
+       {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},              \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},                   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0},          \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},              \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0},                 \
+       {0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), BIT(6)},              \
+       {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},              \
+       {0x0063, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},              \
+       {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},                   \
+       {0x0058, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},              \
+       {0x005A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},              \
+       {0x0068, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3), BIT(3)},              \
+       {0x0069, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), BIT(6)},
+
+#define RTL8723B_TRANS_ACT_TO_CARDEMU                                  \
+       {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},                     \
+       {0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},                   \
+       {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},                   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},              \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0},                 \
+       {0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), 0},                   \
+       {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+        PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC,        \
+        PWR_CMD_WRITE, BIT(5), BIT(5)},                                \
+       {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+        PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC,        \
+        PWR_CMD_WRITE, BIT(0), 0},
+
+#define RTL8723B_TRANS_CARDEMU_TO_SUS                                  \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4) | BIT(3), (BIT(4) | BIT(3))}, \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+        PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC,        \
+        PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)},                       \
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)},              \
+       {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20},                  \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) | BIT(4)},\
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)},             \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0},
+
+#define RTL8723B_TRANS_SUS_TO_CARDEMU                                  \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0},          \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},                  \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},           \
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},                   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},
+
+#define RTL8723B_TRANS_CARDEMU_TO_CARDDIS                              \
+       {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20},                  \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+        PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,                          \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},       \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), BIT(2)},              \
+       {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 1},                   \
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)},              \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)},             \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0},
+
+#define RTL8723B_TRANS_CARDDIS_TO_CARDEMU                              \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0},          \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},                  \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},           \
+       {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},                   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},            \
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},                   \
+       {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},
+
+#define RTL8723B_TRANS_CARDEMU_TO_PDN                                  \
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)},              \
+       {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+        PWR_INTF_SDIO_MSK | PWR_INTF_USB_MSK, PWR_BASEADDR_MAC,        \
+        PWR_CMD_WRITE, 0xFF, 0x20},                                    \
+       {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},                   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},
+
+#define RTL8723B_TRANS_PDN_TO_CARDEMU                                  \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},
+
+#define RTL8723B_TRANS_ACT_TO_LPS                                      \
+       {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},                  \
+       {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},                  \
+       {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},                   \
+       {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},                   \
+       {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},                   \
+       {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},                   \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},                   \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},          \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},                   \
+       {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},                  \
+       {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},                   \
+       {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},                  \
+       {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)},
+
+#define RTL8723B_TRANS_LPS_TO_ACT                                      \
+       {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+        PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84},         \
+       {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},                  \
+       {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},                  \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS},          \
+       {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},                   \
+       {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0},         \
+       {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0},            \
+       {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},              \
+       {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},                  \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1) | BIT(0), BIT(1) | BIT(0)}, \
+       {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+        PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},
+
+#define RTL8723B_TRANS_END                                             \
+       {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, \
+        PWR_CMD_END, 0, 0},
+
+extern struct wlan_pwr_cfg rtl8723B_power_on_flow
+                               [RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS +
+                                RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_radio_off_flow
+                               [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_card_disable_flow
+                               [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+                                RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_card_enable_flow
+                               [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+                                RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_suspend_flow
+                               [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS +
+                                RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_resume_flow
+                               [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS +
+                                RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_hwpdn_flow
+                               [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS +
+                                RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS +
+                                RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_enter_lps_flow
+                               [RTL8723B_TRANS_ACT_TO_LPS_STEPS +
+                                RTL8723B_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723B_leave_lps_flow
+                               [RTL8723B_TRANS_LPS_TO_ACT_STEPS +
+                                RTL8723B_TRANS_END_STEPS];
+
+/* RTL8723 Power Configuration CMDs for PCIe interface */
+#define RTL8723_NIC_PWR_ON_FLOW                rtl8723B_power_on_flow
+#define RTL8723_NIC_RF_OFF_FLOW                rtl8723B_radio_off_flow
+#define RTL8723_NIC_DISABLE_FLOW       rtl8723B_card_disable_flow
+#define RTL8723_NIC_ENABLE_FLOW                rtl8723B_card_enable_flow
+#define RTL8723_NIC_SUSPEND_FLOW       rtl8723B_suspend_flow
+#define RTL8723_NIC_RESUME_FLOW                rtl8723B_resume_flow
+#define RTL8723_NIC_PDN_FLOW           rtl8723B_hwpdn_flow
+#define RTL8723_NIC_LPS_ENTER_FLOW     rtl8723B_enter_lps_flow
+#define RTL8723_NIC_LPS_LEAVE_FLOW     rtl8723B_leave_lps_flow
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c
new file mode 100644 (file)
index 0000000..e4a507a
--- /dev/null
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseq.h"
+
+/*     Description:
+ *             This routine deal with the Power Configuration CMDs
+ *              parsing for RTL8723/RTL8188E Series IC.
+ *     Assumption:
+ *             We should follow specific format which was released from HW SD.
+ *
+ *     2011.07.07, added by Roger.
+ */
+bool rtlbe_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+                                u8 fab_version, u8 interface_type,
+                                struct wlan_pwr_cfg pwrcfgcmd[])
+
+{
+       struct wlan_pwr_cfg pwr_cfg_cmd = {0};
+       bool b_polling_bit = false;
+       u32 ary_idx = 0;
+       u8 value = 0;
+       u32 offset = 0;
+       u32 polling_count = 0;
+       u32 max_polling_cnt = 5000;
+
+       do {
+               pwr_cfg_cmd = pwrcfgcmd[ary_idx];
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "rtlbe_hal_pwrseqcmdparsing(): "
+                        "offset(%#x),cut_msk(%#x), fab_msk(%#x),"
+                        "interface_msk(%#x), base(%#x), "
+                        "cmd(%#x), msk(%#x), value(%#x)\n",
+                        GET_PWR_CFG_OFFSET(pwr_cfg_cmd),
+                        GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd),
+                        GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd),
+                        GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd),
+                        GET_PWR_CFG_BASE(pwr_cfg_cmd),
+                        GET_PWR_CFG_CMD(pwr_cfg_cmd),
+                        GET_PWR_CFG_MASK(pwr_cfg_cmd),
+                        GET_PWR_CFG_VALUE(pwr_cfg_cmd));
+
+               if ((GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd)&fab_version) &&
+                   (GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd)&cut_version) &&
+                   (GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd)&interface_type)) {
+                       switch (GET_PWR_CFG_CMD(pwr_cfg_cmd)) {
+                       case PWR_CMD_READ:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                        "rtlbe_hal_pwrseqcmdparsing(): "
+                                         "PWR_CMD_READ\n");
+                               break;
+                       case PWR_CMD_WRITE:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                        "rtlbe_hal_pwrseqcmdparsing(): "
+                                         "PWR_CMD_WRITE\n");
+                               offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd);
+
+                               /*Read the value from system register*/
+                               value = rtl_read_byte(rtlpriv, offset);
+                               value &= (~(GET_PWR_CFG_MASK(pwr_cfg_cmd)));
+                               value = value | (GET_PWR_CFG_VALUE(pwr_cfg_cmd)
+                                       & GET_PWR_CFG_MASK(pwr_cfg_cmd));
+
+                               /*Write the value back to sytem register*/
+                               rtl_write_byte(rtlpriv, offset, value);
+                               break;
+                       case PWR_CMD_POLLING:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                        "rtlbe_hal_pwrseqcmdparsing(): "
+                                         "PWR_CMD_POLLING\n");
+                               b_polling_bit = false;
+                               offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd);
+
+                               do {
+                                       value = rtl_read_byte(rtlpriv, offset);
+
+                                       value &= GET_PWR_CFG_MASK(pwr_cfg_cmd);
+                                       if (value ==
+                                           (GET_PWR_CFG_VALUE(pwr_cfg_cmd) &
+                                            GET_PWR_CFG_MASK(pwr_cfg_cmd)))
+                                               b_polling_bit = true;
+                                       else
+                                               udelay(10);
+
+                                       if (polling_count++ > max_polling_cnt)
+                                               return false;
+
+                               } while (!b_polling_bit);
+                               break;
+                       case PWR_CMD_DELAY:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                        "rtlbe_hal_pwrseqcmdparsing(): "
+                                        "PWR_CMD_DELAY\n");
+                               if (GET_PWR_CFG_VALUE(pwr_cfg_cmd) ==
+                                   PWRSEQ_DELAY_US)
+                                       udelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd));
+                               else
+                                       mdelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd));
+                               break;
+                       case PWR_CMD_END:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                        "rtlbe_hal_pwrseqcmdparsing(): "
+                                        "PWR_CMD_END\n");
+                               return true;
+                               break;
+                       default:
+                               RT_ASSERT(false,
+                                         "rtlbe_hal_pwrseqcmdparsing(): "
+                                         "Unknown CMD!!\n");
+                               break;
+                       }
+               }
+
+               ary_idx++;
+       } while (1);
+
+       return true;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h
new file mode 100644 (file)
index 0000000..ce14a3b
--- /dev/null
@@ -0,0 +1,95 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_PWRSEQCMD_H__
+#define __RTL8723BE_PWRSEQCMD_H__
+
+#include "../wifi.h"
+/*---------------------------------------------*/
+/*The value of cmd: 4 bits */
+/*---------------------------------------------*/
+#define PWR_CMD_READ           0x00
+#define PWR_CMD_WRITE          0x01
+#define PWR_CMD_POLLING                0x02
+#define PWR_CMD_DELAY          0x03
+#define PWR_CMD_END            0x04
+
+/* define the base address of each block */
+#define PWR_BASEADDR_MAC       0x00
+#define PWR_BASEADDR_USB       0x01
+#define PWR_BASEADDR_PCIE      0x02
+#define PWR_BASEADDR_SDIO      0x03
+
+#define        PWR_INTF_SDIO_MSK       BIT(0)
+#define        PWR_INTF_USB_MSK        BIT(1)
+#define        PWR_INTF_PCI_MSK        BIT(2)
+#define        PWR_INTF_ALL_MSK        (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
+#define        PWR_FAB_TSMC_MSK        BIT(0)
+#define        PWR_FAB_UMC_MSK         BIT(1)
+#define        PWR_FAB_ALL_MSK         (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
+#define        PWR_CUT_TESTCHIP_MSK    BIT(0)
+#define        PWR_CUT_A_MSK           BIT(1)
+#define        PWR_CUT_B_MSK           BIT(2)
+#define        PWR_CUT_C_MSK           BIT(3)
+#define        PWR_CUT_D_MSK           BIT(4)
+#define        PWR_CUT_E_MSK           BIT(5)
+#define        PWR_CUT_F_MSK           BIT(6)
+#define        PWR_CUT_G_MSK           BIT(7)
+#define        PWR_CUT_ALL_MSK         0xFF
+
+
+enum pwrseq_delay_unit {
+       PWRSEQ_DELAY_US,
+       PWRSEQ_DELAY_MS,
+};
+
+struct wlan_pwr_cfg {
+       u16 offset;
+       u8 cut_msk;
+       u8 fab_msk:4;
+       u8 interface_msk:4;
+       u8 base:4;
+       u8 cmd:4;
+       u8 msk;
+       u8 value;
+
+};
+
+#define        GET_PWR_CFG_OFFSET(__PWR_CMD)   __PWR_CMD.offset
+#define        GET_PWR_CFG_CUT_MASK(__PWR_CMD) __PWR_CMD.cut_msk
+#define        GET_PWR_CFG_FAB_MASK(__PWR_CMD) __PWR_CMD.fab_msk
+#define        GET_PWR_CFG_INTF_MASK(__PWR_CMD)        __PWR_CMD.interface_msk
+#define        GET_PWR_CFG_BASE(__PWR_CMD)     __PWR_CMD.base
+#define        GET_PWR_CFG_CMD(__PWR_CMD)      __PWR_CMD.cmd
+#define        GET_PWR_CFG_MASK(__PWR_CMD)     __PWR_CMD.msk
+#define        GET_PWR_CFG_VALUE(__PWR_CMD)    __PWR_CMD.value
+
+bool rtlbe_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+                                u8 fab_version, u8 interface_type,
+                                struct wlan_pwr_cfg pwrcfgcmd[]);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h
new file mode 100644 (file)
index 0000000..4c653fa
--- /dev/null
@@ -0,0 +1,2277 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_REG_H__
+#define __RTL8723BE_REG_H__
+
+#define TXPKT_BUF_SELECT                       0x69
+#define RXPKT_BUF_SELECT                       0xA5
+#define DISABLE_TRXPKT_BUF_ACCESS              0x0
+
+#define REG_SYS_ISO_CTRL                       0x0000
+#define REG_SYS_FUNC_EN                                0x0002
+#define REG_APS_FSMCO                          0x0004
+#define REG_SYS_CLKR                           0x0008
+#define REG_9346CR                             0x000A
+#define REG_EE_VPD                             0x000C
+#define REG_AFE_MISC                           0x0010
+#define REG_SPS0_CTRL                          0x0011
+#define REG_SPS_OCP_CFG                                0x0018
+#define REG_RSV_CTRL                           0x001C
+#define REG_RF_CTRL                            0x001F
+#define REG_LDOA15_CTRL                                0x0020
+#define REG_LDOV12D_CTRL                       0x0021
+#define REG_LDOHCI12_CTRL                      0x0022
+#define REG_LPLDO_CTRL                         0x0023
+#define REG_AFE_XTAL_CTRL                      0x0024
+/* 1.5v for 8188EE test chip, 1.4v for MP chip */
+#define REG_AFE_LDO_CTRL                       0x0027
+#define REG_AFE_PLL_CTRL                       0x0028
+#define REG_MAC_PHY_CTRL                       0x002c
+#define REG_EFUSE_CTRL                         0x0030
+#define REG_EFUSE_TEST                         0x0034
+#define REG_PWR_DATA                           0x0038
+#define REG_CAL_TIMER                          0x003C
+#define REG_ACLK_MON                           0x003E
+#define REG_GPIO_MUXCFG                                0x0040
+#define REG_GPIO_IO_SEL                                0x0042
+#define REG_MAC_PINMUX_CFG                     0x0043
+#define REG_GPIO_PIN_CTRL                      0x0044
+#define REG_GPIO_INTM                          0x0048
+#define REG_LEDCFG0                            0x004C
+#define REG_LEDCFG1                            0x004D
+#define REG_LEDCFG2                            0x004E
+#define REG_LEDCFG3                            0x004F
+#define REG_FSIMR                              0x0050
+#define REG_FSISR                              0x0054
+#define REG_HSIMR                              0x0058
+#define REG_HSISR                              0x005c
+#define REG_GPIO_PIN_CTRL_2                    0x0060
+#define REG_GPIO_IO_SEL_2                      0x0062
+#define REG_MULTI_FUNC_CTRL                    0x0068
+#define REG_GPIO_OUTPUT                                0x006c
+#define REG_AFE_XTAL_CTRL_EXT                  0x0078
+#define REG_XCK_OUT_CTRL                       0x007c
+#define REG_MCUFWDL                            0x0080
+#define REG_WOL_EVENT                          0x0081
+#define REG_MCUTSTCFG                          0x0084
+
+
+#define REG_HIMR                               0x00B0
+#define REG_HISR                               0x00B4
+#define REG_HIMRE                              0x00B8
+#define REG_HISRE                              0x00BC
+
+#define REG_EFUSE_ACCESS                       0x00CF
+
+#define REG_BIST_SCAN                          0x00D0
+#define REG_BIST_RPT                           0x00D4
+#define REG_BIST_ROM_RPT                       0x00D8
+#define REG_USB_SIE_INTF                       0x00E0
+#define REG_PCIE_MIO_INTF                      0x00E4
+#define REG_PCIE_MIO_INTD                      0x00E8
+#define REG_HPON_FSM                           0x00EC
+#define REG_SYS_CFG                            0x00F0
+#define REG_GPIO_OUTSTS                                0x00F4
+#define REG_SYS_CFG1                           0x00F0
+#define REG_ROM_VERSION                                0x00FD
+
+#define REG_CR                                 0x0100
+#define REG_PBP                                        0x0104
+#define REG_PKT_BUFF_ACCESS_CTRL               0x0106
+#define REG_TRXDMA_CTRL                                0x010C
+#define REG_TRXFF_BNDY                         0x0114
+#define REG_TRXFF_STATUS                       0x0118
+#define REG_RXFF_PTR                           0x011C
+
+#define REG_CPWM                               0x012F
+#define REG_FWIMR                              0x0130
+#define REG_FWISR                              0x0134
+#define REG_PKTBUF_DBG_CTRL                    0x0140
+#define REG_PKTBUF_DBG_DATA_L                  0x0144
+#define REG_PKTBUF_DBG_DATA_H                  0x0148
+#define REG_RXPKTBUF_CTRL                      (REG_PKTBUF_DBG_CTRL + 2)
+
+#define REG_TC0_CTRL                           0x0150
+#define REG_TC1_CTRL                           0x0154
+#define REG_TC2_CTRL                           0x0158
+#define REG_TC3_CTRL                           0x015C
+#define REG_TC4_CTRL                           0x0160
+#define REG_TCUNIT_BASE                                0x0164
+#define REG_MBIST_START                                0x0174
+#define REG_MBIST_DONE                         0x0178
+#define REG_MBIST_FAIL                         0x017C
+#define REG_32K_CTRL                           0x0194
+#define REG_C2HEVT_MSG_NORMAL                  0x01A0
+#define REG_C2HEVT_CLEAR                       0x01AF
+#define REG_C2HEVT_MSG_TEST                    0x01B8
+#define REG_MCUTST_1                           0x01c0
+#define REG_FMETHR                             0x01C8
+#define REG_HMETFR                             0x01CC
+#define REG_HMEBOX_0                           0x01D0
+#define REG_HMEBOX_1                           0x01D4
+#define REG_HMEBOX_2                           0x01D8
+#define REG_HMEBOX_3                           0x01DC
+
+#define REG_LLT_INIT                           0x01E0
+#define REG_BB_ACCEESS_CTRL                    0x01E8
+#define REG_BB_ACCESS_DATA                     0x01EC
+
+#define REG_HMEBOX_EXT_0                       0x01F0
+#define REG_HMEBOX_EXT_1                       0x01F4
+#define REG_HMEBOX_EXT_2                       0x01F8
+#define REG_HMEBOX_EXT_3                       0x01FC
+
+#define REG_RQPN                               0x0200
+#define REG_FIFOPAGE                           0x0204
+#define REG_TDECTRL                            0x0208
+#define REG_TXDMA_OFFSET_CHK                   0x020C
+#define REG_TXDMA_STATUS                       0x0210
+#define REG_RQPN_NPQ                           0x0214
+
+#define REG_RXDMA_AGG_PG_TH                    0x0280
+/* FW shall update this register before FW write RXPKT_RELEASE_POLL to 1 */
+#define REG_FW_UPD_RDPTR                       0x0284
+/* Control the RX DMA.*/
+#define REG_RXDMA_CONTROL                      0x0286
+/* The number of packets in RXPKTBUF.  */
+#define REG_RXPKT_NUM                          0x0287
+
+#define        REG_PCIE_CTRL_REG                       0x0300
+#define        REG_INT_MIG                             0x0304
+#define        REG_BCNQ_DESA                           0x0308
+#define        REG_HQ_DESA                             0x0310
+#define        REG_MGQ_DESA                            0x0318
+#define        REG_VOQ_DESA                            0x0320
+#define        REG_VIQ_DESA                            0x0328
+#define        REG_BEQ_DESA                            0x0330
+#define        REG_BKQ_DESA                            0x0338
+#define        REG_RX_DESA                             0x0340
+
+#define        REG_DBI                                 0x0348
+#define        REG_MDIO                                0x0354
+#define        REG_DBG_SEL                             0x0360
+#define        REG_PCIE_HRPWM                          0x0361
+#define        REG_PCIE_HCPWM                          0x0363
+#define        REG_UART_CTRL                           0x0364
+#define        REG_WATCH_DOG                           0x0368
+#define        REG_UART_TX_DESA                        0x0370
+#define        REG_UART_RX_DESA                        0x0378
+
+
+#define        REG_HDAQ_DESA_NODEF                     0x0000
+#define        REG_CMDQ_DESA_NODEF                     0x0000
+
+#define REG_VOQ_INFORMATION                    0x0400
+#define REG_VIQ_INFORMATION                    0x0404
+#define REG_BEQ_INFORMATION                    0x0408
+#define REG_BKQ_INFORMATION                    0x040C
+#define REG_MGQ_INFORMATION                    0x0410
+#define REG_HGQ_INFORMATION                    0x0414
+#define REG_BCNQ_INFORMATION                   0x0418
+#define REG_TXPKT_EMPTY                                0x041A
+
+
+#define REG_CPU_MGQ_INFORMATION                        0x041C
+#define REG_FWHW_TXQ_CTRL                      0x0420
+#define REG_HWSEQ_CTRL                         0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY                 0x0424
+#define REG_TXPKTBUF_MGQ_BDNY                  0x0425
+#define REG_MULTI_BCNQ_EN                      0x0426
+#define REG_MULTI_BCNQ_OFFSET                  0x0427
+#define REG_SPEC_SIFS                          0x0428
+#define REG_RL                                 0x042A
+#define REG_DARFRC                             0x0430
+#define REG_RARFRC                             0x0438
+#define REG_RRSR                               0x0440
+#define REG_ARFR0                              0x0444
+#define REG_ARFR1                              0x0448
+#define REG_ARFR2                              0x044C
+#define REG_ARFR3                              0x0450
+#define REG_AMPDU_MAX_TIME                     0x0456
+#define REG_AGGLEN_LMT                         0x0458
+#define REG_AMPDU_MIN_SPACE                    0x045C
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD            0x045D
+#define REG_FAST_EDCA_CTRL                     0x0460
+#define REG_RD_RESP_PKT_TH                     0x0463
+#define REG_INIRTS_RATE_SEL                    0x0480
+#define REG_INIDATA_RATE_SEL                   0x0484
+#define REG_POWER_STATUS                       0x04A4
+#define REG_POWER_STAGE1                       0x04B4
+#define REG_POWER_STAGE2                       0x04B8
+#define REG_PKT_LIFE_TIME                      0x04C0
+#define REG_STBC_SETTING                       0x04C4
+#define REG_PROT_MODE_CTRL                     0x04C8
+#define REG_BAR_MODE_CTRL                      0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT                        0x04CF
+#define REG_EARLY_MODE_CONTROL                 0x04D0
+#define REG_NQOS_SEQ                           0x04DC
+#define REG_QOS_SEQ                            0x04DE
+#define REG_NEED_CPU_HANDLE                    0x04E0
+#define REG_PKT_LOSE_RPT                       0x04E1
+#define REG_PTCL_ERR_STATUS                    0x04E2
+#define REG_TX_RPT_CTRL                                0x04EC
+#define REG_TX_RPT_TIME                                0x04F0
+#define REG_DUMMY                              0x04FC
+
+#define REG_EDCA_VO_PARAM                      0x0500
+#define REG_EDCA_VI_PARAM                      0x0504
+#define REG_EDCA_BE_PARAM                      0x0508
+#define REG_EDCA_BK_PARAM                      0x050C
+#define REG_BCNTCFG                            0x0510
+#define REG_PIFS                               0x0512
+#define REG_RDG_PIFS                           0x0513
+#define REG_SIFS_CTX                           0x0514
+#define REG_SIFS_TRX                           0x0516
+#define REG_AGGR_BREAK_TIME                    0x051A
+#define REG_SLOT                               0x051B
+#define REG_TX_PTCL_CTRL                       0x0520
+#define REG_TXPAUSE                            0x0522
+#define REG_DIS_TXREQ_CLR                      0x0523
+#define REG_RD_CTRL                            0x0524
+#define REG_TBTT_PROHIBIT                      0x0540
+#define REG_RD_NAV_NXT                         0x0544
+#define REG_NAV_PROT_LEN                       0x0546
+#define REG_BCN_CTRL                           0x0550
+#define REG_USTIME_TSF                         0x0551
+#define REG_MBID_NUM                           0x0552
+#define REG_DUAL_TSF_RST                       0x0553
+#define REG_BCN_INTERVAL                       0x0554
+#define REG_MBSSID_BCN_SPACE                   0x0554
+#define REG_DRVERLYINT                         0x0558
+#define REG_BCNDMATIM                          0x0559
+#define REG_ATIMWND                            0x055A
+#define REG_BCN_MAX_ERR                                0x055D
+#define REG_RXTSF_OFFSET_CCK                   0x055E
+#define REG_RXTSF_OFFSET_OFDM                  0x055F
+#define REG_TSFTR                              0x0560
+#define REG_INIT_TSFTR                         0x0564
+#define REG_SECONDARY_CCA_CTRL                 0x0577
+#define REG_PSTIMER                            0x0580
+#define REG_TIMER0                             0x0584
+#define REG_TIMER1                             0x0588
+#define REG_ACMHWCTRL                          0x05C0
+#define REG_ACMRSTCTRL                         0x05C1
+#define REG_ACMAVG                             0x05C2
+#define REG_VO_ADMTIME                         0x05C4
+#define REG_VI_ADMTIME                         0x05C6
+#define REG_BE_ADMTIME                         0x05C8
+#define REG_EDCA_RANDOM_GEN                    0x05CC
+#define REG_SCH_TXCMD                          0x05D0
+
+#define REG_APSD_CTRL                          0x0600
+#define REG_BWOPMODE                           0x0603
+#define REG_TCR                                        0x0604
+#define REG_RCR                                        0x0608
+#define REG_RX_PKT_LIMIT                       0x060C
+#define REG_RX_DLK_TIME                                0x060D
+#define REG_RX_DRVINFO_SZ                      0x060F
+
+#define REG_MACID                              0x0610
+#define REG_BSSID                              0x0618
+#define REG_MAR                                        0x0620
+#define REG_MBIDCAMCFG                         0x0628
+
+#define REG_USTIME_EDCA                                0x0638
+#define REG_MAC_SPEC_SIFS                      0x063A
+#define REG_RESP_SIFS_CCK                      0x063C
+#define REG_RESP_SIFS_OFDM                     0x063E
+#define REG_ACKTO                              0x0640
+#define REG_CTS2TO                             0x0641
+#define REG_EIFS                               0x0642
+
+#define REG_NAV_CTRL                           0x0650
+#define REG_BACAMCMD                           0x0654
+#define REG_BACAMCONTENT                       0x0658
+#define REG_LBDLY                              0x0660
+#define REG_FWDLY                              0x0661
+#define REG_RXERR_RPT                          0x0664
+#define REG_TRXPTCL_CTL                                0x0668
+
+#define REG_CAMCMD                             0x0670
+#define REG_CAMWRITE                           0x0674
+#define REG_CAMREAD                            0x0678
+#define REG_CAMDBG                             0x067C
+#define REG_SECCFG                             0x0680
+
+#define REG_WOW_CTRL                           0x0690
+#define REG_PSSTATUS                           0x0691
+#define REG_PS_RX_INFO                         0x0692
+#define REG_UAPSD_TID                          0x0693
+#define REG_LPNAV_CTRL                         0x0694
+#define REG_WKFMCAM_NUM                                0x0698
+#define REG_WKFMCAM_RWD                                0x069C
+#define REG_RXFLTMAP0                          0x06A0
+#define REG_RXFLTMAP1                          0x06A2
+#define REG_RXFLTMAP2                          0x06A4
+#define REG_BCN_PSR_RPT                                0x06A8
+#define REG_CALB32K_CTRL                       0x06AC
+#define REG_PKT_MON_CTRL                       0x06B4
+#define REG_BT_COEX_TABLE                      0x06C0
+#define REG_WMAC_RESP_TXINFO                   0x06D8
+
+#define REG_USB_INFO                           0xFE17
+#define REG_USB_SPECIAL_OPTION                 0xFE55
+#define REG_USB_DMA_AGG_TO                     0xFE5B
+#define REG_USB_AGG_TO                         0xFE5C
+#define REG_USB_AGG_TH                         0xFE5D
+
+#define REG_TEST_USB_TXQS                      0xFE48
+#define REG_TEST_SIE_VID                       0xFE60
+#define REG_TEST_SIE_PID                       0xFE62
+#define REG_TEST_SIE_OPTIONAL                  0xFE64
+#define REG_TEST_SIE_CHIRP_K                   0xFE65
+#define REG_TEST_SIE_PHY                       0xFE66
+#define REG_TEST_SIE_MAC_ADDR                  0xFE70
+#define REG_TEST_SIE_STRING                    0xFE80
+
+#define REG_NORMAL_SIE_VID                     0xFE60
+#define REG_NORMAL_SIE_PID                     0xFE62
+#define REG_NORMAL_SIE_OPTIONAL                        0xFE64
+#define REG_NORMAL_SIE_EP                      0xFE65
+#define REG_NORMAL_SIE_PHY                     0xFE68
+#define REG_NORMAL_SIE_MAC_ADDR                        0xFE70
+#define REG_NORMAL_SIE_STRING                  0xFE80
+
+#define        CR9346                                  REG_9346CR
+#define        MSR                                     (REG_CR + 2)
+#define        ISR                                     REG_HISR
+#define        TSFR                                    REG_TSFTR
+
+#define        MACIDR0                                 REG_MACID
+#define        MACIDR4                                 (REG_MACID + 4)
+
+#define PBP                                    REG_PBP
+
+#define        IDR0                                    MACIDR0
+#define        IDR4                                    MACIDR4
+
+#define        UNUSED_REGISTER                         0x1BF
+#define        DCAM                                    UNUSED_REGISTER
+#define        PSR                                     UNUSED_REGISTER
+#define BBADDR                                 UNUSED_REGISTER
+#define        PHYDATAR                                UNUSED_REGISTER
+
+#define        INVALID_BBRF_VALUE                      0x12345678
+
+#define        MAX_MSS_DENSITY_2T                      0x13
+#define        MAX_MSS_DENSITY_1T                      0x0A
+
+#define        CMDEEPROM_EN                            BIT(5)
+#define        CMDEEPROM_SEL                           BIT(4)
+#define        CMD9346CR_9356SEL                       BIT(4)
+#define        AUTOLOAD_EEPROM                         (CMDEEPROM_EN | CMDEEPROM_SEL)
+#define        AUTOLOAD_EFUSE                          CMDEEPROM_EN
+
+#define        GPIOSEL_GPIO                            0
+#define        GPIOSEL_ENBT                            BIT(5)
+
+#define        GPIO_IN                                 REG_GPIO_PIN_CTRL
+#define        GPIO_OUT                                (REG_GPIO_PIN_CTRL + 1)
+#define        GPIO_IO_SEL                             (REG_GPIO_PIN_CTRL + 2)
+#define        GPIO_MOD                                (REG_GPIO_PIN_CTRL + 3)
+
+/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */
+#define        HSIMR_GPIO12_0_INT_EN                   BIT(0)
+#define        HSIMR_SPS_OCP_INT_EN                    BIT(5)
+#define        HSIMR_RON_INT_EN                        BIT(6)
+#define        HSIMR_PDN_INT_EN                        BIT(7)
+#define        HSIMR_GPIO9_INT_EN                      BIT(25)
+
+/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
+
+#define        HSISR_GPIO12_0_INT                      BIT(0)
+#define        HSISR_SPS_OCP_INT                       BIT(5)
+#define        HSISR_RON_INT_EN                        BIT(6)
+#define        HSISR_PDNINT                            BIT(7)
+#define        HSISR_GPIO9_INT                         BIT(25)
+
+#define        MSR_NOLINK                              0x00
+#define        MSR_ADHOC                               0x01
+#define        MSR_INFRA                               0x02
+#define        MSR_AP                                  0x03
+
+#define        RRSR_RSC_OFFSET                         21
+#define        RRSR_SHORT_OFFSET                       23
+#define        RRSR_RSC_BW_40M                         0x600000
+#define        RRSR_RSC_UPSUBCHNL                      0x400000
+#define        RRSR_RSC_LOWSUBCHNL                     0x200000
+#define        RRSR_SHORT                              0x800000
+#define        RRSR_1M                                 BIT(0)
+#define        RRSR_2M                                 BIT(1)
+#define        RRSR_5_5M                               BIT(2)
+#define        RRSR_11M                                BIT(3)
+#define        RRSR_6M                                 BIT(4)
+#define        RRSR_9M                                 BIT(5)
+#define        RRSR_12M                                BIT(6)
+#define        RRSR_18M                                BIT(7)
+#define        RRSR_24M                                BIT(8)
+#define        RRSR_36M                                BIT(9)
+#define        RRSR_48M                                BIT(10)
+#define        RRSR_54M                                BIT(11)
+#define        RRSR_MCS0                               BIT(12)
+#define        RRSR_MCS1                               BIT(13)
+#define        RRSR_MCS2                               BIT(14)
+#define        RRSR_MCS3                               BIT(15)
+#define        RRSR_MCS4                               BIT(16)
+#define        RRSR_MCS5                               BIT(17)
+#define        RRSR_MCS6                               BIT(18)
+#define        RRSR_MCS7                               BIT(19)
+#define        BRSR_ACKSHORTPMB                        BIT(23)
+
+#define        RATR_1M                                 0x00000001
+#define        RATR_2M                                 0x00000002
+#define        RATR_55M                                0x00000004
+#define        RATR_11M                                0x00000008
+#define        RATR_6M                                 0x00000010
+#define        RATR_9M                                 0x00000020
+#define        RATR_12M                                0x00000040
+#define        RATR_18M                                0x00000080
+#define        RATR_24M                                0x00000100
+#define        RATR_36M                                0x00000200
+#define        RATR_48M                                0x00000400
+#define        RATR_54M                                0x00000800
+#define        RATR_MCS0                               0x00001000
+#define        RATR_MCS1                               0x00002000
+#define        RATR_MCS2                               0x00004000
+#define        RATR_MCS3                               0x00008000
+#define        RATR_MCS4                               0x00010000
+#define        RATR_MCS5                               0x00020000
+#define        RATR_MCS6                               0x00040000
+#define        RATR_MCS7                               0x00080000
+#define        RATR_MCS8                               0x00100000
+#define        RATR_MCS9                               0x00200000
+#define        RATR_MCS10                              0x00400000
+#define        RATR_MCS11                              0x00800000
+#define        RATR_MCS12                              0x01000000
+#define        RATR_MCS13                              0x02000000
+#define        RATR_MCS14                              0x04000000
+#define        RATR_MCS15                              0x08000000
+
+#define RATE_1M                                        BIT(0)
+#define RATE_2M                                        BIT(1)
+#define RATE_5_5M                              BIT(2)
+#define RATE_11M                               BIT(3)
+#define RATE_6M                                        BIT(4)
+#define RATE_9M                                        BIT(5)
+#define RATE_12M                               BIT(6)
+#define RATE_18M                               BIT(7)
+#define RATE_24M                               BIT(8)
+#define RATE_36M                               BIT(9)
+#define RATE_48M                               BIT(10)
+#define RATE_54M                               BIT(11)
+#define RATE_MCS0                              BIT(12)
+#define RATE_MCS1                              BIT(13)
+#define RATE_MCS2                              BIT(14)
+#define RATE_MCS3                              BIT(15)
+#define RATE_MCS4                              BIT(16)
+#define RATE_MCS5                              BIT(17)
+#define RATE_MCS6                              BIT(18)
+#define RATE_MCS7                              BIT(19)
+#define RATE_MCS8                              BIT(20)
+#define RATE_MCS9                              BIT(21)
+#define RATE_MCS10                             BIT(22)
+#define RATE_MCS11                             BIT(23)
+#define RATE_MCS12                             BIT(24)
+#define RATE_MCS13                             BIT(25)
+#define RATE_MCS14                             BIT(26)
+#define RATE_MCS15                             BIT(27)
+
+#define        RATE_ALL_CCK            (RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define        RATE_ALL_OFDM_AG        (RATR_6M | RATR_9M | RATR_12M | RATR_18M |\
+                                RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define        RATE_ALL_OFDM_1SS       (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |\
+                                RATR_MCS3 | RATR_MCS4 | RATR_MCS5 |\
+                                RATR_MCS6 | RATR_MCS7)
+#define        RATE_ALL_OFDM_2SS       (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 |\
+                                RATR_MCS11 | RATR_MCS12 | RATR_MCS13 |\
+                                RATR_MCS14 | RATR_MCS15)
+
+#define        BW_OPMODE_20MHZ                         BIT(2)
+#define        BW_OPMODE_5G                            BIT(1)
+#define        BW_OPMODE_11J                           BIT(0)
+
+#define        CAM_VALID                               BIT(15)
+#define        CAM_NOTVALID                            0x0000
+#define        CAM_USEDK                               BIT(5)
+
+#define        CAM_NONE                                0x0
+#define        CAM_WEP40                               0x01
+#define        CAM_TKIP                                0x02
+#define        CAM_AES                                 0x04
+#define        CAM_WEP104                              0x05
+
+#define        TOTAL_CAM_ENTRY                         32
+#define        HALF_CAM_ENTRY                          16
+
+#define        CAM_WRITE                               BIT(16)
+#define        CAM_READ                                0x00000000
+#define        CAM_POLLINIG                            BIT(31)
+
+#define        SCR_USEDK                               0x01
+#define        SCR_TXSEC_ENABLE                        0x02
+#define        SCR_RXSEC_ENABLE                        0x04
+
+#define        WOW_PMEN                                BIT(0)
+#define        WOW_WOMEN                               BIT(1)
+#define        WOW_MAGIC                               BIT(2)
+#define        WOW_UWF                                 BIT(3)
+
+/*********************************************
+*       8723BE IMR/ISR bits
+**********************************************/
+#define        IMR_DISABLED                            0x0
+/* IMR DW0(0x0060-0063) Bit 0-31 */
+#define        IMR_TXCCK               BIT(30) /* TXRPT interrupt when
+                                        * CCX bit of the packet is set
+                                        */
+#define        IMR_PSTIMEOUT           BIT(29) /* Power Save Time Out Interrupt */
+#define        IMR_GTINT4              BIT(28) /* When GTIMER4 expires,
+                                        * this bit is set to 1
+                                        */
+#define        IMR_GTINT3              BIT(27) /* When GTIMER3 expires,
+                                        * this bit is set to 1
+                                        */
+#define        IMR_TBDER               BIT(26) /* Transmit Beacon0 Error */
+#define        IMR_TBDOK               BIT(25) /* Transmit Beacon0 OK */
+#define        IMR_TSF_BIT32_TOGGLE    BIT(24) /* TSF Timer BIT32 toggle
+                                        * indication interrupt
+                                        */
+#define        IMR_BCNDMAINT0          BIT(20) /* Beacon DMA Interrupt 0 */
+#define        IMR_BCNDOK0             BIT(16) /* Beacon Queue DMA OK0 */
+#define        IMR_HSISR_IND_ON_INT    BIT(15) /* HSISR Indicator (HSIMR & HSISR is
+                                        * true, this bit is set to 1)
+                                        */
+#define        IMR_BCNDMAINT_E         BIT(14) /* Beacon DMA Interrupt
+                                        * Extension for Win7
+                                        */
+#define        IMR_ATIMEND             BIT(12) /* CTWidnow End or ATIM Window End */
+#define        IMR_HISR1_IND_INT       BIT(11) /* HISR1 Indicator (HISR1 & HIMR1 is
+                                        * true, this bit is set to 1)
+                                        */
+#define        IMR_C2HCMD              BIT(10) /* CPU to Host Command INT Status,
+                                        * Write 1 clear
+                                        */
+#define        IMR_CPWM2               BIT(9)  /* CPU power Mode exchange INT Status,
+                                        * Write 1 clear
+                                        */
+#define        IMR_CPWM                BIT(8)  /* CPU power Mode exchange INT Status,
+                                        * Write 1 clear
+                                        */
+#define        IMR_HIGHDOK             BIT(7)  /* High Queue DMA OK */
+#define        IMR_MGNTDOK             BIT(6)  /* Management Queue DMA OK */
+#define        IMR_BKDOK               BIT(5)  /* AC_BK DMA OK */
+#define        IMR_BEDOK               BIT(4)  /* AC_BE DMA OK */
+#define        IMR_VIDOK               BIT(3)  /* AC_VI DMA OK */
+#define        IMR_VODOK               BIT(2)  /* AC_VO DMA OK */
+#define        IMR_RDU                 BIT(1)  /* Rx Descriptor Unavailable */
+#define        IMR_ROK                 BIT(0)  /* Receive DMA OK */
+
+/* IMR DW1(0x00B4-00B7) Bit 0-31 */
+#define        IMR_BCNDMAINT7          BIT(27) /* Beacon DMA Interrupt 7 */
+#define        IMR_BCNDMAINT6          BIT(26) /* Beacon DMA Interrupt 6 */
+#define        IMR_BCNDMAINT5          BIT(25) /* Beacon DMA Interrupt 5 */
+#define        IMR_BCNDMAINT4          BIT(24) /* Beacon DMA Interrupt 4 */
+#define        IMR_BCNDMAINT3          BIT(23) /* Beacon DMA Interrupt 3 */
+#define        IMR_BCNDMAINT2          BIT(22) /* Beacon DMA Interrupt 2 */
+#define        IMR_BCNDMAINT1          BIT(21) /* Beacon DMA Interrupt 1 */
+#define        IMR_BCNDOK7             BIT(20) /* Beacon Queue DMA OK Interrup 7 */
+#define        IMR_BCNDOK6             BIT(19) /* Beacon Queue DMA OK Interrup 6 */
+#define        IMR_BCNDOK5             BIT(18) /* Beacon Queue DMA OK Interrup 5 */
+#define        IMR_BCNDOK4             BIT(17) /* Beacon Queue DMA OK Interrup 4 */
+#define        IMR_BCNDOK3             BIT(16) /* Beacon Queue DMA OK Interrup 3 */
+#define        IMR_BCNDOK2             BIT(15) /* Beacon Queue DMA OK Interrup 2 */
+#define        IMR_BCNDOK1             BIT(14) /* Beacon Queue DMA OK Interrup 1 */
+#define        IMR_ATIMEND_E           BIT(13) /* ATIM Window End Extension for Win7 */
+#define        IMR_TXERR               BIT(11) /* Tx Error Flag Interrupt Status,
+                                        * write 1 clear.
+                                        */
+#define        IMR_RXERR               BIT(10) /* Rx Error Flag INT Status,
+                                        * Write 1 clear
+                                        */
+#define        IMR_TXFOVW              BIT(9)  /* Transmit FIFO Overflow */
+#define        IMR_RXFOVW              BIT(8)  /* Receive FIFO Overflow */
+
+#define        HWSET_MAX_SIZE                  512
+#define EFUSE_MAX_SECTION              64
+#define EFUSE_REAL_CONTENT_LEN         256
+#define EFUSE_OOB_PROTECT_BYTES                18 /* PG data exclude header,
+                                           * dummy 7 bytes frome CP test
+                                           * and reserved 1byte.
+                                           */
+
+#define        EEPROM_DEFAULT_TSSI                     0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF             0x0
+#define EEPROM_DEFAULT_CRYSTALCAP              0x5
+#define EEPROM_DEFAULT_BOARDTYPE               0x02
+#define EEPROM_DEFAULT_TXPOWER                 0x1010
+#define        EEPROM_DEFAULT_HT2T_TXPWR               0x10
+
+#define        EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF      0x3
+#define        EEPROM_DEFAULT_THERMALMETER             0x18
+#define        EEPROM_DEFAULT_ANTTXPOWERDIFF           0x0
+#define        EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP      0x5
+#define        EEPROM_DEFAULT_TXPOWERLEVEL             0x22
+#define        EEPROM_DEFAULT_HT40_2SDIFF              0x0
+#define EEPROM_DEFAULT_HT20_DIFF               2
+#define        EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF      0x3
+#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET       0
+#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET       0
+
+#define RF_OPTION1                             0x79
+#define RF_OPTION2                             0x7A
+#define RF_OPTION3                             0x7B
+#define RF_OPTION4                             0xC3
+
+#define EEPROM_DEFAULT_PID                     0x1234
+#define EEPROM_DEFAULT_VID                     0x5678
+#define EEPROM_DEFAULT_CUSTOMERID              0xAB
+#define EEPROM_DEFAULT_SUBCUSTOMERID           0xCD
+#define EEPROM_DEFAULT_VERSION                 0
+
+#define        EEPROM_CHANNEL_PLAN_FCC                 0x0
+#define        EEPROM_CHANNEL_PLAN_IC                  0x1
+#define        EEPROM_CHANNEL_PLAN_ETSI                0x2
+#define        EEPROM_CHANNEL_PLAN_SPAIN               0x3
+#define        EEPROM_CHANNEL_PLAN_FRANCE              0x4
+#define        EEPROM_CHANNEL_PLAN_MKK                 0x5
+#define        EEPROM_CHANNEL_PLAN_MKK1                0x6
+#define        EEPROM_CHANNEL_PLAN_ISRAEL              0x7
+#define        EEPROM_CHANNEL_PLAN_TELEC               0x8
+#define        EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN       0x9
+#define        EEPROM_CHANNEL_PLAN_WORLD_WIDE_13       0xA
+#define        EEPROM_CHANNEL_PLAN_NCC                 0xB
+#define        EEPROM_CHANNEL_PLAN_BY_HW_MASK          0x80
+
+#define EEPROM_CID_DEFAULT                     0x0
+#define EEPROM_CID_TOSHIBA                     0x4
+#define        EEPROM_CID_CCX                          0x10
+#define        EEPROM_CID_QMI                          0x0D
+#define EEPROM_CID_WHQL                                0xFE
+
+#define        RTL8723BE_EEPROM_ID                     0x8129
+
+#define EEPROM_HPON                            0x02
+#define EEPROM_CLK                             0x06
+#define EEPROM_TESTR                           0x08
+
+
+#define EEPROM_TXPOWERCCK                      0x10
+#define        EEPROM_TXPOWERHT40_1S                   0x16
+#define EEPROM_TXPOWERHT20DIFF                 0x1B
+#define EEPROM_TXPOWER_OFDMDIFF                        0x1B
+
+
+
+#define        EEPROM_TX_PWR_INX                       0x10
+
+#define        EEPROM_CHANNELPLAN                      0xB8
+#define        EEPROM_XTAL_8723BE                      0xB9
+#define        EEPROM_THERMAL_METER_88E                0xBA
+#define        EEPROM_IQK_LCK_88E                      0xBB
+
+#define        EEPROM_RF_BOARD_OPTION_88E              0xC1
+#define        EEPROM_RF_FEATURE_OPTION_88E            0xC2
+#define        EEPROM_RF_BT_SETTING_88E                0xC3
+#define        EEPROM_VERSION                          0xC4
+#define        EEPROM_CUSTOMER_ID                      0xC5
+#define        EEPROM_RF_ANTENNA_OPT_88E               0xC9
+
+#define        EEPROM_MAC_ADDR                         0xD0
+#define EEPROM_VID                             0xD6
+#define EEPROM_DID                             0xD8
+#define EEPROM_SVID                            0xDA
+#define EEPROM_SMID                            0xDC
+
+#define        STOPBECON                               BIT(6)
+#define        STOPHIGHT                               BIT(5)
+#define        STOPMGT                                 BIT(4)
+#define        STOPVO                                  BIT(3)
+#define        STOPVI                                  BIT(2)
+#define        STOPBE                                  BIT(1)
+#define        STOPBK                                  BIT(0)
+
+#define        RCR_APPFCS                              BIT(31)
+#define        RCR_APP_MIC                             BIT(30)
+#define        RCR_APP_ICV                             BIT(29)
+#define        RCR_APP_PHYST_RXFF                      BIT(28)
+#define        RCR_APP_BA_SSN                          BIT(27)
+#define        RCR_ENMBID                              BIT(24)
+#define        RCR_LSIGEN                              BIT(23)
+#define        RCR_MFBEN                               BIT(22)
+#define        RCR_HTC_LOC_CTRL                        BIT(14)
+#define        RCR_AMF                                 BIT(13)
+#define        RCR_ACF                                 BIT(12)
+#define        RCR_ADF                                 BIT(11)
+#define        RCR_AICV                                BIT(9)
+#define        RCR_ACRC32                              BIT(8)
+#define        RCR_CBSSID_BCN                          BIT(7)
+#define        RCR_CBSSID_DATA                         BIT(6)
+#define        RCR_CBSSID                              RCR_CBSSID_DATA
+#define        RCR_APWRMGT                             BIT(5)
+#define        RCR_ADD3                                BIT(4)
+#define        RCR_AB                                  BIT(3)
+#define        RCR_AM                                  BIT(2)
+#define        RCR_APM                                 BIT(1)
+#define        RCR_AAP                                 BIT(0)
+#define        RCR_MXDMA_OFFSET                        8
+#define        RCR_FIFO_OFFSET                         13
+
+#define RSV_CTRL                               0x001C
+#define RD_CTRL                                        0x0524
+
+#define REG_USB_INFO                           0xFE17
+#define REG_USB_SPECIAL_OPTION                 0xFE55
+#define REG_USB_DMA_AGG_TO                     0xFE5B
+#define REG_USB_AGG_TO                         0xFE5C
+#define REG_USB_AGG_TH                         0xFE5D
+
+#define REG_USB_VID                            0xFE60
+#define REG_USB_PID                            0xFE62
+#define REG_USB_OPTIONAL                       0xFE64
+#define REG_USB_CHIRP_K                                0xFE65
+#define REG_USB_PHY                            0xFE66
+#define REG_USB_MAC_ADDR                       0xFE70
+#define REG_USB_HRPWM                          0xFE58
+#define REG_USB_HCPWM                          0xFE57
+
+#define SW18_FPWM                              BIT(3)
+
+#define ISO_MD2PP                              BIT(0)
+#define ISO_UA2USB                             BIT(1)
+#define ISO_UD2CORE                            BIT(2)
+#define ISO_PA2PCIE                            BIT(3)
+#define ISO_PD2CORE                            BIT(4)
+#define ISO_IP2MAC                             BIT(5)
+#define ISO_DIOP                               BIT(6)
+#define ISO_DIOE                               BIT(7)
+#define ISO_EB2CORE                            BIT(8)
+#define ISO_DIOR                               BIT(9)
+
+#define PWC_EV25V                              BIT(14)
+#define PWC_EV12V                              BIT(15)
+
+#define FEN_BBRSTB                             BIT(0)
+#define FEN_BB_GLB_RSTN                                BIT(1)
+#define FEN_USBA                               BIT(2)
+#define FEN_UPLL                               BIT(3)
+#define FEN_USBD                               BIT(4)
+#define FEN_DIO_PCIE                           BIT(5)
+#define FEN_PCIEA                              BIT(6)
+#define FEN_PPLL                               BIT(7)
+#define FEN_PCIED                              BIT(8)
+#define FEN_DIOE                               BIT(9)
+#define FEN_CPUEN                              BIT(10)
+#define FEN_DCORE                              BIT(11)
+#define FEN_ELDR                               BIT(12)
+#define FEN_DIO_RF                             BIT(13)
+#define FEN_HWPDN                              BIT(14)
+#define FEN_MREGEN                             BIT(15)
+
+#define PFM_LDALL                              BIT(0)
+#define PFM_ALDN                               BIT(1)
+#define PFM_LDKP                               BIT(2)
+#define PFM_WOWL                               BIT(3)
+#define ENPDN                                  BIT(4)
+#define PDN_PL                                 BIT(5)
+#define APFM_ONMAC                             BIT(8)
+#define APFM_OFF                               BIT(9)
+#define APFM_RSM                               BIT(10)
+#define AFSM_HSUS                              BIT(11)
+#define AFSM_PCIE                              BIT(12)
+#define APDM_MAC                               BIT(13)
+#define APDM_HOST                              BIT(14)
+#define APDM_HPDN                              BIT(15)
+#define RDY_MACON                              BIT(16)
+#define SUS_HOST                               BIT(17)
+#define ROP_ALD                                        BIT(20)
+#define ROP_PWR                                        BIT(21)
+#define ROP_SPS                                        BIT(22)
+#define SOP_MRST                               BIT(25)
+#define SOP_FUSE                               BIT(26)
+#define SOP_ABG                                        BIT(27)
+#define SOP_AMB                                        BIT(28)
+#define SOP_RCK                                        BIT(29)
+#define SOP_A8M                                        BIT(30)
+#define XOP_BTCK                               BIT(31)
+
+#define ANAD16V_EN                             BIT(0)
+#define ANA8M                                  BIT(1)
+#define MACSLP                                 BIT(4)
+#define LOADER_CLK_EN                          BIT(5)
+#define _80M_SSC_DIS                           BIT(7)
+#define _80M_SSC_EN_HO                         BIT(8)
+#define PHY_SSC_RSTB                           BIT(9)
+#define SEC_CLK_EN                             BIT(10)
+#define MAC_CLK_EN                             BIT(11)
+#define SYS_CLK_EN                             BIT(12)
+#define RING_CLK_EN                            BIT(13)
+
+#define        BOOT_FROM_EEPROM                        BIT(4)
+#define        EEPROM_EN                               BIT(5)
+
+#define AFE_BGEN                               BIT(0)
+#define AFE_MBEN                               BIT(1)
+#define MAC_ID_EN                              BIT(7)
+
+#define WLOCK_ALL                              BIT(0)
+#define WLOCK_00                               BIT(1)
+#define WLOCK_04                               BIT(2)
+#define WLOCK_08                               BIT(3)
+#define WLOCK_40                               BIT(4)
+#define R_DIS_PRST_0                           BIT(5)
+#define R_DIS_PRST_1                           BIT(6)
+#define LOCK_ALL_EN                            BIT(7)
+
+#define RF_EN                                  BIT(0)
+#define RF_RSTB                                        BIT(1)
+#define RF_SDMRSTB                             BIT(2)
+
+#define LDA15_EN                               BIT(0)
+#define LDA15_STBY                             BIT(1)
+#define LDA15_OBUF                             BIT(2)
+#define LDA15_REG_VOS                          BIT(3)
+#define _LDA15_VOADJ(x)                                (((x) & 0x7) << 4)
+
+#define LDV12_EN                               BIT(0)
+#define LDV12_SDBY                             BIT(1)
+#define LPLDO_HSM                              BIT(2)
+#define LPLDO_LSM_DIS                          BIT(3)
+#define _LDV12_VADJ(x)                         (((x) & 0xF) << 4)
+
+#define XTAL_EN                                        BIT(0)
+#define XTAL_BSEL                              BIT(1)
+#define _XTAL_BOSC(x)                          (((x) & 0x3) << 2)
+#define _XTAL_CADJ(x)                          (((x) & 0xF) << 4)
+#define XTAL_GATE_USB                          BIT(8)
+#define _XTAL_USB_DRV(x)                       (((x) & 0x3) << 9)
+#define XTAL_GATE_AFE                          BIT(11)
+#define _XTAL_AFE_DRV(x)                       (((x) & 0x3) << 12)
+#define XTAL_RF_GATE                           BIT(14)
+#define _XTAL_RF_DRV(x)                                (((x) & 0x3) << 15)
+#define XTAL_GATE_DIG                          BIT(17)
+#define _XTAL_DIG_DRV(x)                       (((x) & 0x3) << 18)
+#define XTAL_BT_GATE                           BIT(20)
+#define _XTAL_BT_DRV(x)                                (((x) & 0x3) << 21)
+#define _XTAL_GPIO(x)                          (((x) & 0x7) << 23)
+
+#define CKDLY_AFE                              BIT(26)
+#define CKDLY_USB                              BIT(27)
+#define CKDLY_DIG                              BIT(28)
+#define CKDLY_BT                               BIT(29)
+
+#define APLL_EN                                        BIT(0)
+#define APLL_320_EN                            BIT(1)
+#define APLL_FREF_SEL                          BIT(2)
+#define APLL_EDGE_SEL                          BIT(3)
+#define APLL_WDOGB                             BIT(4)
+#define APLL_LPFEN                             BIT(5)
+
+#define APLL_REF_CLK_13MHZ                     0x1
+#define APLL_REF_CLK_19_2MHZ                   0x2
+#define APLL_REF_CLK_20MHZ                     0x3
+#define APLL_REF_CLK_25MHZ                     0x4
+#define APLL_REF_CLK_26MHZ                     0x5
+#define APLL_REF_CLK_38_4MHZ                   0x6
+#define APLL_REF_CLK_40MHZ                     0x7
+
+#define APLL_320EN                             BIT(14)
+#define APLL_80EN                              BIT(15)
+#define APLL_1MEN                              BIT(24)
+
+#define ALD_EN                                 BIT(18)
+#define EF_PD                                  BIT(19)
+#define EF_FLAG                                        BIT(31)
+
+#define EF_TRPT                                        BIT(7)
+#define LDOE25_EN                              BIT(31)
+
+#define RSM_EN                                 BIT(0)
+#define TIMER_EN                               BIT(4)
+
+#define TRSW0EN                                        BIT(2)
+#define TRSW1EN                                        BIT(3)
+#define EROM_EN                                        BIT(4)
+#define ENBT                                   BIT(5)
+#define ENUART                                 BIT(8)
+#define UART_910                               BIT(9)
+#define ENPMAC                                 BIT(10)
+#define SIC_SWRST                              BIT(11)
+#define ENSIC                                  BIT(12)
+#define SIC_23                                 BIT(13)
+#define ENHDP                                  BIT(14)
+#define SIC_LBK                                        BIT(15)
+
+#define LED0PL                                 BIT(4)
+#define LED1PL                                 BIT(12)
+#define LED0DIS                                        BIT(7)
+
+#define MCUFWDL_EN                             BIT(0)
+#define MCUFWDL_RDY                            BIT(1)
+#define FWDL_CHKSUM_RPT                                BIT(2)
+#define MACINI_RDY                             BIT(3)
+#define BBINI_RDY                              BIT(4)
+#define RFINI_RDY                              BIT(5)
+#define WINTINI_RDY                            BIT(6)
+#define CPRST                                  BIT(23)
+
+#define XCLK_VLD                               BIT(0)
+#define ACLK_VLD                               BIT(1)
+#define UCLK_VLD                               BIT(2)
+#define PCLK_VLD                               BIT(3)
+#define PCIRSTB                                        BIT(4)
+#define V15_VLD                                        BIT(5)
+#define TRP_B15V_EN                            BIT(7)
+#define SIC_IDLE                               BIT(8)
+#define BD_MAC2                                        BIT(9)
+#define BD_MAC1                                        BIT(10)
+#define IC_MACPHY_MODE                         BIT(11)
+#define VENDOR_ID                              BIT(19)
+#define PAD_HWPD_IDN                           BIT(22)
+#define TRP_VAUX_EN                            BIT(23)
+#define TRP_BT_EN                              BIT(24)
+#define BD_PKG_SEL                             BIT(25)
+#define BD_HCI_SEL                             BIT(26)
+#define TYPE_ID                                        BIT(27)
+
+#define CHIP_VER_RTL_MASK                      0xF000
+#define CHIP_VER_RTL_SHIFT                     12
+
+#define REG_LBMODE                             (REG_CR + 3)
+
+#define HCI_TXDMA_EN                           BIT(0)
+#define HCI_RXDMA_EN                           BIT(1)
+#define TXDMA_EN                               BIT(2)
+#define RXDMA_EN                               BIT(3)
+#define PROTOCOL_EN                            BIT(4)
+#define SCHEDULE_EN                            BIT(5)
+#define MACTXEN                                        BIT(6)
+#define MACRXEN                                        BIT(7)
+#define ENSWBCN                                        BIT(8)
+#define ENSEC                                  BIT(9)
+
+#define _NETTYPE(x)                            (((x) & 0x3) << 16)
+#define MASK_NETTYPE                           0x30000
+#define NT_NO_LINK                             0x0
+#define NT_LINK_AD_HOC                         0x1
+#define NT_LINK_AP                             0x2
+#define NT_AS_AP                               0x3
+
+#define _LBMODE(x)                             (((x) & 0xF) << 24)
+#define MASK_LBMODE                            0xF000000
+#define LOOPBACK_NORMAL                                0x0
+#define LOOPBACK_IMMEDIATELY                   0xB
+#define LOOPBACK_MAC_DELAY                     0x3
+#define LOOPBACK_PHY                           0x1
+#define LOOPBACK_DMA                           0x7
+
+#define GET_RX_PAGE_SIZE(value)                        ((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value)                        (((value) & 0xF0) >> 4)
+#define _PSRX_MASK                             0xF
+#define _PSTX_MASK                             0xF0
+#define _PSRX(x)                               (x)
+#define _PSTX(x)                               ((x) << 4)
+
+#define PBP_64                                 0x0
+#define PBP_128                                        0x1
+#define PBP_256                                        0x2
+#define PBP_512                                        0x3
+#define PBP_1024                               0x4
+
+#define RXDMA_ARBBW_EN                         BIT(0)
+#define RXSHFT_EN                              BIT(1)
+#define RXDMA_AGG_EN                           BIT(2)
+#define QS_VO_QUEUE                            BIT(8)
+#define QS_VI_QUEUE                            BIT(9)
+#define QS_BE_QUEUE                            BIT(10)
+#define QS_BK_QUEUE                            BIT(11)
+#define QS_MANAGER_QUEUE                       BIT(12)
+#define QS_HIGH_QUEUE                          BIT(13)
+
+#define HQSEL_VOQ                              BIT(0)
+#define HQSEL_VIQ                              BIT(1)
+#define HQSEL_BEQ                              BIT(2)
+#define HQSEL_BKQ                              BIT(3)
+#define HQSEL_MGTQ                             BIT(4)
+#define HQSEL_HIQ                              BIT(5)
+
+#define _TXDMA_HIQ_MAP(x)                      (((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x)                      (((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x)                      (((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x)                      (((x)&0x3) << 8)
+#define _TXDMA_VIQ_MAP(x)                      (((x)&0x3) << 6)
+#define _TXDMA_VOQ_MAP(x)                      (((x)&0x3) << 4)
+
+#define QUEUE_LOW                              1
+#define QUEUE_NORMAL                           2
+#define QUEUE_HIGH                             3
+
+#define _LLT_NO_ACTIVE                         0x0
+#define _LLT_WRITE_ACCESS                      0x1
+#define _LLT_READ_ACCESS                       0x2
+
+#define _LLT_INIT_DATA(x)                      ((x) & 0xFF)
+#define _LLT_INIT_ADDR(x)                      (((x) & 0xFF) << 8)
+#define _LLT_OP(x)                             (((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x)                       (((x) >> 30) & 0x3)
+
+#define BB_WRITE_READ_MASK                     (BIT(31) | BIT(30))
+#define BB_WRITE_EN                            BIT(30)
+#define BB_READ_EN                             BIT(31)
+
+#define _HPQ(x)                                        ((x) & 0xFF)
+#define _LPQ(x)                                        (((x) & 0xFF) << 8)
+#define _PUBQ(x)                               (((x) & 0xFF) << 16)
+#define _NPQ(x)                                        ((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS                         BIT(24)
+#define LPQ_PUBLIC_DIS                         BIT(25)
+#define LD_RQPN                                        BIT(31)
+
+#define BCN_VALID                              BIT(16)
+#define BCN_HEAD(x)                            (((x) & 0xFF) << 8)
+#define        BCN_HEAD_MASK                           0xFF00
+
+#define BLK_DESC_NUM_SHIFT                     4
+#define BLK_DESC_NUM_MASK                      0xF
+
+#define DROP_DATA_EN                           BIT(9)
+
+#define EN_AMPDU_RTY_NEW                       BIT(7)
+
+#define _INIRTSMCS_SEL(x)                      ((x) & 0x3F)
+
+#define _SPEC_SIFS_CCK(x)                      ((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x)                     (((x) & 0xFF) << 8)
+
+#define RATE_REG_BITMAP_ALL                    0xFFFFF
+
+#define _RRSC_BITMAP(x)                                ((x) & 0xFFFFF)
+
+#define _RRSR_RSC(x)                           (((x) & 0x3) << 21)
+#define RRSR_RSC_RESERVED                      0x0
+#define RRSR_RSC_UPPER_SUBCHANNEL              0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL              0x2
+#define RRSR_RSC_DUPLICATE_MODE                        0x3
+
+#define USE_SHORT_G1                           BIT(20)
+
+#define _AGGLMT_MCS0(x)                                ((x) & 0xF)
+#define _AGGLMT_MCS1(x)                                (((x) & 0xF) << 4)
+#define _AGGLMT_MCS2(x)                                (((x) & 0xF) << 8)
+#define _AGGLMT_MCS3(x)                                (((x) & 0xF) << 12)
+#define _AGGLMT_MCS4(x)                                (((x) & 0xF) << 16)
+#define _AGGLMT_MCS5(x)                                (((x) & 0xF) << 20)
+#define _AGGLMT_MCS6(x)                                (((x) & 0xF) << 24)
+#define _AGGLMT_MCS7(x)                                (((x) & 0xF) << 28)
+
+#define        RETRY_LIMIT_SHORT_SHIFT                 8
+#define        RETRY_LIMIT_LONG_SHIFT                  0
+
+#define _DARF_RC1(x)                           ((x) & 0x1F)
+#define _DARF_RC2(x)                           (((x) & 0x1F) << 8)
+#define _DARF_RC3(x)                           (((x) & 0x1F) << 16)
+#define _DARF_RC4(x)                           (((x) & 0x1F) << 24)
+#define _DARF_RC5(x)                           ((x) & 0x1F)
+#define _DARF_RC6(x)                           (((x) & 0x1F) << 8)
+#define _DARF_RC7(x)                           (((x) & 0x1F) << 16)
+#define _DARF_RC8(x)                           (((x) & 0x1F) << 24)
+
+#define _RARF_RC1(x)                           ((x) & 0x1F)
+#define _RARF_RC2(x)                           (((x) & 0x1F) << 8)
+#define _RARF_RC3(x)                           (((x) & 0x1F) << 16)
+#define _RARF_RC4(x)                           (((x) & 0x1F) << 24)
+#define _RARF_RC5(x)                           ((x) & 0x1F)
+#define _RARF_RC6(x)                           (((x) & 0x1F) << 8)
+#define _RARF_RC7(x)                           (((x) & 0x1F) << 16)
+#define _RARF_RC8(x)                           (((x) & 0x1F) << 24)
+
+#define AC_PARAM_TXOP_LIMIT_OFFSET             16
+#define AC_PARAM_ECW_MAX_OFFSET                        12
+#define AC_PARAM_ECW_MIN_OFFSET                        8
+#define AC_PARAM_AIFS_OFFSET                   0
+
+#define _AIFS(x)                               (x)
+#define _ECW_MAX_MIN(x)                                ((x) << 8)
+#define _TXOP_LIMIT(x)                         ((x) << 16)
+
+#define _BCNIFS(x)                             ((x) & 0xFF)
+#define _BCNECW(x)                             ((((x) & 0xF)) << 8)
+
+#define _LRL(x)                                        ((x) & 0x3F)
+#define _SRL(x)                                        (((x) & 0x3F) << 8)
+
+#define _SIFS_CCK_CTX(x)                       ((x) & 0xFF)
+#define _SIFS_CCK_TRX(x)                       (((x) & 0xFF) << 8)
+
+#define _SIFS_OFDM_CTX(x)                      ((x) & 0xFF)
+#define _SIFS_OFDM_TRX(x)                      (((x) & 0xFF) << 8)
+
+#define _TBTT_PROHIBIT_HOLD(x)                 (((x) & 0xFF) << 8)
+
+#define DIS_EDCA_CNT_DWN                       BIT(11)
+
+#define EN_MBSSID                              BIT(1)
+#define EN_TXBCN_RPT                           BIT(2)
+#define        EN_BCN_FUNCTION                         BIT(3)
+
+#define TSFTR_RST                              BIT(0)
+#define TSFTR1_RST                             BIT(1)
+
+#define STOP_BCNQ                              BIT(6)
+
+#define        DIS_TSF_UDT0_NORMAL_CHIP                BIT(4)
+#define        DIS_TSF_UDT0_TEST_CHIP                  BIT(5)
+
+#define        ACMHW_HWEN                              BIT(0)
+#define        ACMHW_BEQEN                             BIT(1)
+#define        ACMHW_VIQEN                             BIT(2)
+#define        ACMHW_VOQEN                             BIT(3)
+#define        ACMHW_BEQSTATUS                         BIT(4)
+#define        ACMHW_VIQSTATUS                         BIT(5)
+#define        ACMHW_VOQSTATUS                         BIT(6)
+
+#define APSDOFF                                        BIT(6)
+#define APSDOFF_STATUS                         BIT(7)
+
+#define BW_20MHZ                               BIT(2)
+
+#define RATE_BITMAP_ALL                                0xFFFFF
+
+#define RATE_RRSR_CCK_ONLY_1M                  0xFFFF1
+
+#define TSFRST                                 BIT(0)
+#define DIS_GCLK                               BIT(1)
+#define PAD_SEL                                        BIT(2)
+#define PWR_ST                                 BIT(6)
+#define PWRBIT_OW_EN                           BIT(7)
+#define ACRC                                   BIT(8)
+#define CFENDFORM                              BIT(9)
+#define ICV                                    BIT(10)
+
+#define AAP                                    BIT(0)
+#define APM                                    BIT(1)
+#define AM                                     BIT(2)
+#define AB                                     BIT(3)
+#define ADD3                                   BIT(4)
+#define APWRMGT                                        BIT(5)
+#define CBSSID                                 BIT(6)
+#define CBSSID_DATA                            BIT(6)
+#define CBSSID_BCN                             BIT(7)
+#define ACRC32                                 BIT(8)
+#define AICV                                   BIT(9)
+#define ADF                                    BIT(11)
+#define ACF                                    BIT(12)
+#define AMF                                    BIT(13)
+#define HTC_LOC_CTRL                           BIT(14)
+#define UC_DATA_EN                             BIT(16)
+#define BM_DATA_EN                             BIT(17)
+#define MFBEN                                  BIT(22)
+#define LSIGEN                                 BIT(23)
+#define ENMBID                                 BIT(24)
+#define APP_BASSN                              BIT(27)
+#define APP_PHYSTS                             BIT(28)
+#define APP_ICV                                        BIT(29)
+#define APP_MIC                                        BIT(30)
+#define APP_FCS                                        BIT(31)
+
+#define _MIN_SPACE(x)                  ((x) & 0x7)
+#define _SHORT_GI_PADDING(x)           (((x) & 0x1F) << 3)
+
+#define RXERR_TYPE_OFDM_PPDU           0
+#define RXERR_TYPE_OFDM_FALSE_ALARM    1
+#define        RXERR_TYPE_OFDM_MPDU_OK         2
+#define RXERR_TYPE_OFDM_MPDU_FAIL      3
+#define RXERR_TYPE_CCK_PPDU            4
+#define RXERR_TYPE_CCK_FALSE_ALARM     5
+#define RXERR_TYPE_CCK_MPDU_OK         6
+#define RXERR_TYPE_CCK_MPDU_FAIL       7
+#define RXERR_TYPE_HT_PPDU             8
+#define RXERR_TYPE_HT_FALSE_ALARM      9
+#define RXERR_TYPE_HT_MPDU_TOTAL       10
+#define RXERR_TYPE_HT_MPDU_OK          11
+#define RXERR_TYPE_HT_MPDU_FAIL                12
+#define RXERR_TYPE_RX_FULL_DROP                15
+
+#define RXERR_COUNTER_MASK             0xFFFFF
+#define RXERR_RPT_RST                  BIT(27)
+#define _RXERR_RPT_SEL(type)           ((type) << 28)
+
+#define        SCR_TXUSEDK                     BIT(0)
+#define        SCR_RXUSEDK                     BIT(1)
+#define        SCR_TXENCENABLE                 BIT(2)
+#define        SCR_RXDECENABLE                 BIT(3)
+#define        SCR_SKBYA2                      BIT(4)
+#define        SCR_NOSKMC                      BIT(5)
+#define SCR_TXBCUSEDK                  BIT(6)
+#define SCR_RXBCUSEDK                  BIT(7)
+
+#define XCLK_VLD                       BIT(0)
+#define ACLK_VLD                       BIT(1)
+#define UCLK_VLD                       BIT(2)
+#define PCLK_VLD                       BIT(3)
+#define PCIRSTB                                BIT(4)
+#define V15_VLD                                BIT(5)
+#define TRP_B15V_EN                    BIT(7)
+#define SIC_IDLE                       BIT(8)
+#define BD_MAC2                                BIT(9)
+#define BD_MAC1                                BIT(10)
+#define IC_MACPHY_MODE                 BIT(11)
+#define BT_FUNC                                BIT(16)
+#define VENDOR_ID                      BIT(19)
+#define PAD_HWPD_IDN                   BIT(22)
+#define TRP_VAUX_EN                    BIT(23)
+#define TRP_BT_EN                      BIT(24)
+#define BD_PKG_SEL                     BIT(25)
+#define BD_HCI_SEL                     BIT(26)
+#define TYPE_ID                                BIT(27)
+
+#define USB_IS_HIGH_SPEED              0
+#define USB_IS_FULL_SPEED              1
+#define USB_SPEED_MASK                 BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK         0xF
+#define USB_NORMAL_SIE_EP_SHIFT                4
+
+#define USB_TEST_EP_MASK               0x30
+#define USB_TEST_EP_SHIFT              4
+
+#define USB_AGG_EN                     BIT(3)
+
+#define MAC_ADDR_LEN                   6
+#define LAST_ENTRY_OF_TX_PKT_BUFFER    175/*255    88e*/
+
+#define POLLING_LLT_THRESHOLD          20
+#define POLLING_READY_TIMEOUT_COUNT    3000
+
+#define        MAX_MSS_DENSITY_2T              0x13
+#define        MAX_MSS_DENSITY_1T              0x0A
+
+#define EPROM_CMD_OPERATING_MODE_MASK  ((1<<7)|(1<<6))
+#define EPROM_CMD_CONFIG               0x3
+#define EPROM_CMD_LOAD                 1
+
+#define        HWSET_MAX_SIZE_92S              HWSET_MAX_SIZE
+
+#define        HAL_8192C_HW_GPIO_WPS_BIT       BIT(2)
+
+#define        RPMAC_RESET                     0x100
+#define        RPMAC_TXSTART                   0x104
+#define        RPMAC_TXLEGACYSIG               0x108
+#define        RPMAC_TXHTSIG1                  0x10c
+#define        RPMAC_TXHTSIG2                  0x110
+#define        RPMAC_PHYDEBUG                  0x114
+#define        RPMAC_TXPACKETNUM               0x118
+#define        RPMAC_TXIDLE                    0x11c
+#define        RPMAC_TXMACHEADER0              0x120
+#define        RPMAC_TXMACHEADER1              0x124
+#define        RPMAC_TXMACHEADER2              0x128
+#define        RPMAC_TXMACHEADER3              0x12c
+#define        RPMAC_TXMACHEADER4              0x130
+#define        RPMAC_TXMACHEADER5              0x134
+#define        RPMAC_TXDADATYPE                0x138
+#define        RPMAC_TXRANDOMSEED              0x13c
+#define        RPMAC_CCKPLCPPREAMBLE           0x140
+#define        RPMAC_CCKPLCPHEADER             0x144
+#define        RPMAC_CCKCRC16                  0x148
+#define        RPMAC_OFDMRXCRC32OK             0x170
+#define        RPMAC_OFDMRXCRC32ER             0x174
+#define        RPMAC_OFDMRXPARITYER            0x178
+#define        RPMAC_OFDMRXCRC8ER              0x17c
+#define        RPMAC_CCKCRXRC16ER              0x180
+#define        RPMAC_CCKCRXRC32ER              0x184
+#define        RPMAC_CCKCRXRC32OK              0x188
+#define        RPMAC_TXSTATUS                  0x18c
+
+#define        RFPGA0_RFMOD                    0x800
+
+#define        RFPGA0_TXINFO                   0x804
+#define        RFPGA0_PSDFUNCTION              0x808
+
+#define        RFPGA0_TXGAINSTAGE              0x80c
+
+#define        RFPGA0_RFTIMING1                0x810
+#define        RFPGA0_RFTIMING2                0x814
+
+#define        RFPGA0_XA_HSSIPARAMETER1        0x820
+#define        RFPGA0_XA_HSSIPARAMETER2        0x824
+#define        RFPGA0_XB_HSSIPARAMETER1        0x828
+#define        RFPGA0_XB_HSSIPARAMETER2        0x82c
+
+#define        RFPGA0_XA_LSSIPARAMETER         0x840
+#define        RFPGA0_XB_LSSIPARAMETER         0x844
+
+#define        RFPGA0_RFWAKEUPPARAMETER        0x850
+#define        RFPGA0_RFSLEEPUPPARAMETER       0x854
+
+#define        RFPGA0_XAB_SWITCHCONTROL        0x858
+#define        RFPGA0_XCD_SWITCHCONTROL        0x85c
+
+#define        RFPGA0_XA_RFINTERFACEOE         0x860
+#define        RFPGA0_XB_RFINTERFACEOE         0x864
+
+#define        RFPGA0_XAB_RFINTERFACESW        0x870
+#define        RFPGA0_XCD_RFINTERFACESW        0x874
+
+#define        RFPGA0_XAB_RFPARAMETER          0x878
+#define        RFPGA0_XCD_RFPARAMETER          0x87c
+
+#define        RFPGA0_ANALOGPARAMETER1         0x880
+#define        RFPGA0_ANALOGPARAMETER2         0x884
+#define        RFPGA0_ANALOGPARAMETER3         0x888
+#define        RFPGA0_ANALOGPARAMETER4         0x88c
+
+#define        RFPGA0_XA_LSSIREADBACK          0x8a0
+#define        RFPGA0_XB_LSSIREADBACK          0x8a4
+#define        RFPGA0_XC_LSSIREADBACK          0x8a8
+#define        RFPGA0_XD_LSSIREADBACK          0x8ac
+
+#define        RFPGA0_PSDREPORT                0x8b4
+#define        TRANSCEIVEA_HSPI_READBACK       0x8b8
+#define        TRANSCEIVEB_HSPI_READBACK       0x8bc
+#define        REG_SC_CNT                      0x8c4
+#define        RFPGA0_XAB_RFINTERFACERB        0x8e0
+#define        RFPGA0_XCD_RFINTERFACERB        0x8e4
+
+#define        RFPGA1_RFMOD                    0x900
+
+#define        RFPGA1_TXBLOCK                  0x904
+#define        RFPGA1_DEBUGSELECT              0x908
+#define        RFPGA1_TXINFO                   0x90c
+
+#define        RCCK0_SYSTEM                    0xa00
+
+#define        RCCK0_AFESETTING                0xa04
+#define        RCCK0_CCA                       0xa08
+
+#define        RCCK0_RXAGC1                    0xa0c
+#define        RCCK0_RXAGC2                    0xa10
+
+#define        RCCK0_RXHP                      0xa14
+
+#define        RCCK0_DSPPARAMETER1             0xa18
+#define        RCCK0_DSPPARAMETER2             0xa1c
+
+#define        RCCK0_TXFILTER1                 0xa20
+#define        RCCK0_TXFILTER2                 0xa24
+#define        RCCK0_DEBUGPORT                 0xa28
+#define        RCCK0_FALSEALARMREPORT          0xa2c
+#define        RCCK0_TRSSIREPORT               0xa50
+#define        RCCK0_RXREPORT                  0xa54
+#define        RCCK0_FACOUNTERLOWER            0xa5c
+#define        RCCK0_FACOUNTERUPPER            0xa58
+#define        RCCK0_CCA_CNT                   0xa60
+
+
+/* PageB(0xB00) */
+#define        RPDP_ANTA                       0xb00
+#define        RPDP_ANTA_4                     0xb04
+#define        RPDP_ANTA_8                     0xb08
+#define        RPDP_ANTA_C                     0xb0c
+#define        RPDP_ANTA_10                    0xb10
+#define        RPDP_ANTA_14                    0xb14
+#define        RPDP_ANTA_18                    0xb18
+#define        RPDP_ANTA_1C                    0xb1c
+#define        RPDP_ANTA_20                    0xb20
+#define        RPDP_ANTA_24                    0xb24
+
+#define        RCONFIG_PMPD_ANTA               0xb28
+#define        CONFIG_RAM64X16                 0xb2c
+
+#define        RBNDA                           0xb30
+#define        RHSSIPAR                        0xb34
+
+#define        RCONFIG_ANTA                    0xb68
+#define        RCONFIG_ANTB                    0xb6c
+
+#define        RPDP_ANTB                       0xb70
+#define        RPDP_ANTB_4                     0xb74
+#define        RPDP_ANTB_8                     0xb78
+#define        RPDP_ANTB_C                     0xb7c
+#define        RPDP_ANTB_10                    0xb80
+#define        RPDP_ANTB_14                    0xb84
+#define        RPDP_ANTB_18                    0xb88
+#define        RPDP_ANTB_1C                    0xb8c
+#define        RPDP_ANTB_20                    0xb90
+#define        RPDP_ANTB_24                    0xb94
+
+#define        RCONFIG_PMPD_ANTB               0xb98
+
+#define        RBNDB                           0xba0
+
+#define        RAPK                            0xbd8
+#define        RPM_RX0_ANTA                    0xbdc
+#define        RPM_RX1_ANTA                    0xbe0
+#define        RPM_RX2_ANTA                    0xbe4
+#define        RPM_RX3_ANTA                    0xbe8
+#define        RPM_RX0_ANTB                    0xbec
+#define        RPM_RX1_ANTB                    0xbf0
+#define        RPM_RX2_ANTB                    0xbf4
+#define        RPM_RX3_ANTB                    0xbf8
+
+/*Page C*/
+#define        ROFDM0_LSTF                     0xc00
+
+#define        ROFDM0_TRXPATHENABLE            0xc04
+#define        ROFDM0_TRMUXPAR                 0xc08
+#define        ROFDM0_TRSWISOLATION            0xc0c
+
+#define        ROFDM0_XARXAFE                  0xc10
+#define        ROFDM0_XARXIQIMBALANCE          0xc14
+#define        ROFDM0_XBRXAFE                  0xc18
+#define        ROFDM0_XBRXIQIMBALANCE          0xc1c
+#define        ROFDM0_XCRXAFE                  0xc20
+#define        ROFDM0_XCRXIQIMBANLANCE         0xc24
+#define        ROFDM0_XDRXAFE                  0xc28
+#define        ROFDM0_XDRXIQIMBALANCE          0xc2c
+
+#define        ROFDM0_RXDETECTOR1              0xc30
+#define        ROFDM0_RXDETECTOR2              0xc34
+#define        ROFDM0_RXDETECTOR3              0xc38
+#define        ROFDM0_RXDETECTOR4              0xc3c
+
+#define        ROFDM0_RXDSP                    0xc40
+#define        ROFDM0_CFOANDDAGC               0xc44
+#define        ROFDM0_CCADROPTHRESHOLD         0xc48
+#define        ROFDM0_ECCATHRESHOLD            0xc4c
+
+#define        ROFDM0_XAAGCCORE1               0xc50
+#define        ROFDM0_XAAGCCORE2               0xc54
+#define        ROFDM0_XBAGCCORE1               0xc58
+#define        ROFDM0_XBAGCCORE2               0xc5c
+#define        ROFDM0_XCAGCCORE1               0xc60
+#define        ROFDM0_XCAGCCORE2               0xc64
+#define        ROFDM0_XDAGCCORE1               0xc68
+#define        ROFDM0_XDAGCCORE2               0xc6c
+
+#define        ROFDM0_AGCPARAMETER1            0xc70
+#define        ROFDM0_AGCPARAMETER2            0xc74
+#define        ROFDM0_AGCRSSITABLE             0xc78
+#define        ROFDM0_HTSTFAGC                 0xc7c
+
+#define        ROFDM0_XATXIQIMBALANCE          0xc80
+#define        ROFDM0_XATXAFE                  0xc84
+#define        ROFDM0_XBTXIQIMBALANCE          0xc88
+#define        ROFDM0_XBTXAFE                  0xc8c
+#define        ROFDM0_XCTXIQIMBALANCE          0xc90
+#define        ROFDM0_XCTXAFE                  0xc94
+#define        ROFDM0_XDTXIQIMBALANCE          0xc98
+#define        ROFDM0_XDTXAFE                  0xc9c
+
+#define ROFDM0_RXIQEXTANTA             0xca0
+#define        ROFDM0_TXCOEFF1                 0xca4
+#define        ROFDM0_TXCOEFF2                 0xca8
+#define        ROFDM0_TXCOEFF3                 0xcac
+#define        ROFDM0_TXCOEFF4                 0xcb0
+#define        ROFDM0_TXCOEFF5                 0xcb4
+#define        ROFDM0_TXCOEFF6                 0xcb8
+
+#define        ROFDM0_RXHPPARAMETER            0xce0
+#define        ROFDM0_TXPSEUDONOISEWGT         0xce4
+#define        ROFDM0_FRAMESYNC                0xcf0
+#define        ROFDM0_DFSREPORT                0xcf4
+
+
+#define        ROFDM1_LSTF                     0xd00
+#define        ROFDM1_TRXPATHENABLE            0xd04
+
+#define        ROFDM1_CF0                      0xd08
+#define        ROFDM1_CSI1                     0xd10
+#define        ROFDM1_SBD                      0xd14
+#define        ROFDM1_CSI2                     0xd18
+#define        ROFDM1_CFOTRACKING              0xd2c
+#define        ROFDM1_TRXMESAURE1              0xd34
+#define        ROFDM1_INTFDET                  0xd3c
+#define        ROFDM1_PSEUDONOISESTATEAB       0xd50
+#define        ROFDM1_PSEUDONOISESTATECD       0xd54
+#define        ROFDM1_RXPSEUDONOISEWGT         0xd58
+
+#define        ROFDM_PHYCOUNTER1               0xda0
+#define        ROFDM_PHYCOUNTER2               0xda4
+#define        ROFDM_PHYCOUNTER3               0xda8
+
+#define        ROFDM_SHORTCFOAB                0xdac
+#define        ROFDM_SHORTCFOCD                0xdb0
+#define        ROFDM_LONGCFOAB                 0xdb4
+#define        ROFDM_LONGCFOCD                 0xdb8
+#define        ROFDM_TAILCF0AB                 0xdbc
+#define        ROFDM_TAILCF0CD                 0xdc0
+#define        ROFDM_PWMEASURE1                0xdc4
+#define        ROFDM_PWMEASURE2                0xdc8
+#define        ROFDM_BWREPORT                  0xdcc
+#define        ROFDM_AGCREPORT                 0xdd0
+#define        ROFDM_RXSNR                     0xdd4
+#define        ROFDM_RXEVMCSI                  0xdd8
+#define        ROFDM_SIGREPORT                 0xddc
+
+#define        RTXAGC_A_RATE18_06              0xe00
+#define        RTXAGC_A_RATE54_24              0xe04
+#define        RTXAGC_A_CCK1_MCS32             0xe08
+#define        RTXAGC_A_MCS03_MCS00            0xe10
+#define        RTXAGC_A_MCS07_MCS04            0xe14
+#define        RTXAGC_A_MCS11_MCS08            0xe18
+#define        RTXAGC_A_MCS15_MCS12            0xe1c
+
+#define        RTXAGC_B_RATE18_06              0x830
+#define        RTXAGC_B_RATE54_24              0x834
+#define        RTXAGC_B_CCK1_55_MCS32          0x838
+#define        RTXAGC_B_MCS03_MCS00            0x83c
+#define        RTXAGC_B_MCS07_MCS04            0x848
+#define        RTXAGC_B_MCS11_MCS08            0x84c
+#define        RTXAGC_B_MCS15_MCS12            0x868
+#define        RTXAGC_B_CCK11_A_CCK2_11        0x86c
+
+#define        RFPGA0_IQK                      0xe28
+#define        RTX_IQK_TONE_A                  0xe30
+#define        RRX_IQK_TONE_A                  0xe34
+#define        RTX_IQK_PI_A                    0xe38
+#define        RRX_IQK_PI_A                    0xe3c
+
+#define        RTX_IQK                         0xe40
+#define        RRX_IQK                         0xe44
+#define        RIQK_AGC_PTS                    0xe48
+#define        RIQK_AGC_RSP                    0xe4c
+#define        RTX_IQK_TONE_B                  0xe50
+#define        RRX_IQK_TONE_B                  0xe54
+#define        RTX_IQK_PI_B                    0xe58
+#define        RRX_IQK_PI_B                    0xe5c
+#define        RIQK_AGC_CONT                   0xe60
+
+#define        RBLUE_TOOTH                     0xe6c
+#define        RRX_WAIT_CCA                    0xe70
+#define        RTX_CCK_RFON                    0xe74
+#define        RTX_CCK_BBON                    0xe78
+#define        RTX_OFDM_RFON                   0xe7c
+#define        RTX_OFDM_BBON                   0xe80
+#define        RTX_TO_RX                       0xe84
+#define        RTX_TO_TX                       0xe88
+#define        RRX_CCK                         0xe8c
+
+#define        RTX_POWER_BEFORE_IQK_A          0xe94
+#define        RTX_POWER_AFTER_IQK_A           0xe9c
+
+#define        RRX_POWER_BEFORE_IQK_A          0xea0
+#define        RRX_POWER_BEFORE_IQK_A_2        0xea4
+#define        RRX_POWER_AFTER_IQK_A           0xea8
+#define        RRX_POWER_AFTER_IQK_A_2         0xeac
+
+#define        RTX_POWER_BEFORE_IQK_B          0xeb4
+#define        RTX_POWER_AFTER_IQK_B           0xebc
+
+#define        RRX_POWER_BEFORE_IQK_B          0xec0
+#define        RRX_POWER_BEFORE_IQK_B_2        0xec4
+#define        RRX_POWER_AFTER_IQK_B           0xec8
+#define        RRX_POWER_AFTER_IQK_B_2         0xecc
+
+#define        RRX_OFDM                        0xed0
+#define        RRX_WAIT_RIFS                   0xed4
+#define        RRX_TO_RX                       0xed8
+#define        RSTANDBY                        0xedc
+#define        RSLEEP                          0xee0
+#define        RPMPD_ANAEN                     0xeec
+
+#define        RZEBRA1_HSSIENABLE              0x0
+#define        RZEBRA1_TRXENABLE1              0x1
+#define        RZEBRA1_TRXENABLE2              0x2
+#define        RZEBRA1_AGC                     0x4
+#define        RZEBRA1_CHARGEPUMP              0x5
+#define        RZEBRA1_CHANNEL                 0x7
+
+#define        RZEBRA1_TXGAIN                  0x8
+#define        RZEBRA1_TXLPF                   0x9
+#define        RZEBRA1_RXLPF                   0xb
+#define        RZEBRA1_RXHPFCORNER             0xc
+
+#define        RGLOBALCTRL                     0
+#define        RRTL8256_TXLPF                  19
+#define        RRTL8256_RXLPF                  11
+#define        RRTL8258_TXLPF                  0x11
+#define        RRTL8258_RXLPF                  0x13
+#define        RRTL8258_RSSILPF                0xa
+
+#define        RF_AC                           0x00
+
+#define        RF_IQADJ_G1                     0x01
+#define        RF_IQADJ_G2                     0x02
+#define        RF_POW_TRSW                     0x05
+
+#define        RF_GAIN_RX                      0x06
+#define        RF_GAIN_TX                      0x07
+
+#define        RF_TXM_IDAC                     0x08
+#define        RF_BS_IQGEN                     0x0F
+
+#define        RF_MODE1                        0x10
+#define        RF_MODE2                        0x11
+
+#define        RF_RX_AGC_HP                    0x12
+#define        RF_TX_AGC                       0x13
+#define        RF_BIAS                         0x14
+#define        RF_IPA                          0x15
+#define        RF_POW_ABILITY                  0x17
+#define        RF_MODE_AG                      0x18
+#define        RRFCHANNEL                      0x18
+#define        RF_CHNLBW                       0x18
+#define        RF_TOP                          0x19
+
+#define        RF_RX_G1                        0x1A
+#define        RF_RX_G2                        0x1B
+
+#define        RF_RX_BB2                       0x1C
+#define        RF_RX_BB1                       0x1D
+
+#define        RF_RCK1                         0x1E
+#define        RF_RCK2                         0x1F
+
+#define        RF_TX_G1                        0x20
+#define        RF_TX_G2                        0x21
+#define        RF_TX_G3                        0x22
+
+#define        RF_TX_BB1                       0x23
+#define        RF_T_METER                      0x42
+
+#define        RF_SYN_G1                       0x25
+#define        RF_SYN_G2                       0x26
+#define        RF_SYN_G3                       0x27
+#define        RF_SYN_G4                       0x28
+#define        RF_SYN_G5                       0x29
+#define        RF_SYN_G6                       0x2A
+#define        RF_SYN_G7                       0x2B
+#define        RF_SYN_G8                       0x2C
+
+#define        RF_RCK_OS                       0x30
+#define        RF_TXPA_G1                      0x31
+#define        RF_TXPA_G2                      0x32
+#define        RF_TXPA_G3                      0x33
+
+#define        RF_TX_BIAS_A                    0x35
+#define        RF_TX_BIAS_D                    0x36
+#define        RF_LOBF_9                       0x38
+#define        RF_RXRF_A3                      0x3C
+#define        RF_TRSW                         0x3F
+
+#define        RF_TXRF_A2                      0x41
+#define        RF_TXPA_G4                      0x46
+#define        RF_TXPA_A4                      0x4B
+
+#define        RF_WE_LUT                       0xEF
+
+#define        BBBRESETB                       0x100
+#define        BGLOBALRESETB                   0x200
+#define        BOFDMTXSTART                    0x4
+#define        BCCKTXSTART                     0x8
+#define        BCRC32DEBUG                     0x100
+#define        BPMACLOOPBACK                   0x10
+#define        BTXLSIG                         0xffffff
+#define        BOFDMTXRATE                     0xf
+#define        BOFDMTXRESERVED                 0x10
+#define        BOFDMTXLENGTH                   0x1ffe0
+#define        BOFDMTXPARITY                   0x20000
+#define        BTXHTSIG1                       0xffffff
+#define        BTXHTMCSRATE                    0x7f
+#define        BTXHTBW                         0x80
+#define        BTXHTLENGTH                     0xffff00
+#define        BTXHTSIG2                       0xffffff
+#define        BTXHTSMOOTHING                  0x1
+#define        BTXHTSOUNDING                   0x2
+#define        BTXHTRESERVED                   0x4
+#define        BTXHTAGGREATION                 0x8
+#define        BTXHTSTBC                       0x30
+#define        BTXHTADVANCECODING              0x40
+#define        BTXHTSHORTGI                    0x80
+#define        BTXHTNUMBERHT_LTF               0x300
+#define        BTXHTCRC8                       0x3fc00
+#define        BCOUNTERRESET                   0x10000
+#define        BNUMOFOFDMTX                    0xffff
+#define        BNUMOFCCKTX                     0xffff0000
+#define        BTXIDLEINTERVAL                 0xffff
+#define        BOFDMSERVICE                    0xffff0000
+#define        BTXMACHEADER                    0xffffffff
+#define        BTXDATAINIT                     0xff
+#define        BTXHTMODE                       0x100
+#define        BTXDATATYPE                     0x30000
+#define        BTXRANDOMSEED                   0xffffffff
+#define        BCCKTXPREAMBLE                  0x1
+#define        BCCKTXSFD                       0xffff0000
+#define        BCCKTXSIG                       0xff
+#define        BCCKTXSERVICE                   0xff00
+#define        BCCKLENGTHEXT                   0x8000
+#define        BCCKTXLENGHT                    0xffff0000
+#define        BCCKTXCRC16                     0xffff
+#define        BCCKTXSTATUS                    0x1
+#define        BOFDMTXSTATUS                   0x2
+#define IS_BB_REG_OFFSET_92S(_offset)  \
+       ((_offset >= 0x800) && (_offset <= 0xfff))
+
+#define        BRFMOD                          0x1
+#define        BJAPANMODE                      0x2
+#define        BCCKTXSC                        0x30
+#define        BCCKEN                          0x1000000
+#define        BOFDMEN                         0x2000000
+
+#define        BOFDMRXADCPHASE                 0x10000
+#define        BOFDMTXDACPHASE                 0x40000
+#define        BXATXAGC                        0x3f
+
+#define        BXBTXAGC                        0xf00
+#define        BXCTXAGC                        0xf000
+#define        BXDTXAGC                        0xf0000
+
+#define        BPASTART                        0xf0000000
+#define        BTRSTART                        0x00f00000
+#define        BRFSTART                        0x0000f000
+#define        BBBSTART                        0x000000f0
+#define        BBBCCKSTART                     0x0000000f
+#define        BPAEND                          0xf
+#define        BTREND                          0x0f000000
+#define        BRFEND                          0x000f0000
+#define        BCCAMASK                        0x000000f0
+#define        BR2RCCAMASK                     0x00000f00
+#define        BHSSI_R2TDELAY                  0xf8000000
+#define        BHSSI_T2RDELAY                  0xf80000
+#define        BCONTXHSSI                      0x400
+#define        BIGFROMCCK                      0x200
+#define        BAGCADDRESS                     0x3f
+#define        BRXHPTX                         0x7000
+#define        BRXHP2RX                        0x38000
+#define        BRXHPCCKINI                     0xc0000
+#define        BAGCTXCODE                      0xc00000
+#define        BAGCRXCODE                      0x300000
+
+#define        B3WIREDATALENGTH                0x800
+#define        B3WIREADDREAALENGTH             0x400
+
+#define        B3WIRERFPOWERDOWN               0x1
+#define        B5GPAPEPOLARITY                 0x40000000
+#define        B2GPAPEPOLARITY                 0x80000000
+#define        BRFSW_TXDEFAULTANT              0x3
+#define        BRFSW_TXOPTIONANT               0x30
+#define        BRFSW_RXDEFAULTANT              0x300
+#define        BRFSW_RXOPTIONANT               0x3000
+#define        BRFSI_3WIREDATA                 0x1
+#define        BRFSI_3WIRECLOCK                0x2
+#define        BRFSI_3WIRELOAD                 0x4
+#define        BRFSI_3WIRERW                   0x8
+#define        BRFSI_3WIRE                     0xf
+
+#define        BRFSI_RFENV                     0x10
+
+#define        BRFSI_TRSW                      0x20
+#define        BRFSI_TRSWB                     0x40
+#define        BRFSI_ANTSW                     0x100
+#define        BRFSI_ANTSWB                    0x200
+#define        BRFSI_PAPE                      0x400
+#define        BRFSI_PAPE5G                    0x800
+#define        BBANDSELECT                     0x1
+#define        BHTSIG2_GI                      0x80
+#define        BHTSIG2_SMOOTHING               0x01
+#define        BHTSIG2_SOUNDING                0x02
+#define        BHTSIG2_AGGREATON               0x08
+#define        BHTSIG2_STBC                    0x30
+#define        BHTSIG2_ADVCODING               0x40
+#define        BHTSIG2_NUMOFHTLTF              0x300
+#define        BHTSIG2_CRC8                    0x3fc
+#define        BHTSIG1_MCS                     0x7f
+#define        BHTSIG1_BANDWIDTH               0x80
+#define        BHTSIG1_HTLENGTH                0xffff
+#define        BLSIG_RATE                      0xf
+#define        BLSIG_RESERVED                  0x10
+#define        BLSIG_LENGTH                    0x1fffe
+#define        BLSIG_PARITY                    0x20
+#define        BCCKRXPHASE                     0x4
+
+#define        BLSSIREADADDRESS                0x7f800000
+#define        BLSSIREADEDGE                   0x80000000
+
+#define        BLSSIREADBACKDATA               0xfffff
+
+#define        BLSSIREADOKFLAG                 0x1000
+#define        BCCKSAMPLERATE                  0x8
+#define        BREGULATOR0STANDBY              0x1
+#define        BREGULATORPLLSTANDBY            0x2
+#define        BREGULATOR1STANDBY              0x4
+#define        BPLLPOWERUP                     0x8
+#define        BDPLLPOWERUP                    0x10
+#define        BDA10POWERUP                    0x20
+#define        BAD7POWERUP                     0x200
+#define        BDA6POWERUP                     0x2000
+#define        BXTALPOWERUP                    0x4000
+#define        B40MDCLKPOWERUP                 0x8000
+#define        BDA6DEBUGMODE                   0x20000
+#define        BDA6SWING                       0x380000
+
+#define        BADCLKPHASE                     0x4000000
+#define        B80MCLKDELAY    0x18000000
+#define        BAFEWATCHDOGENABLE      0x20000000
+
+#define        BXTALCAP01      0xc0000000
+#define        BXTALCAP23      0x3
+#define        BXTALCAP92X                     0x0f000000
+#define BXTALCAP       0x0f000000
+
+#define        BINTDIFCLKENABLE                0x400
+#define        BEXTSIGCLKENABLE                0x800
+#define        BBANDGAP_MBIAS_POWERUP          0x10000
+#define        BAD11SH_GAIN                    0xc0000
+#define        BAD11NPUT_RANGE                 0x700000
+#define        BAD110P_CURRENT                 0x3800000
+#define        BLPATH_LOOPBACK                 0x4000000
+#define        BQPATH_LOOPBACK                 0x8000000
+#define        BAFE_LOOPBACK                   0x10000000
+#define        BDA10_SWING                     0x7e0
+#define        BDA10_REVERSE                   0x800
+#define        BDA_CLK_SOURCE                  0x1000
+#define        BDA7INPUT_RANGE                 0x6000
+#define        BDA7_GAIN                       0x38000
+#define        BDA7OUTPUT_CM_MODE              0x40000
+#define        BDA7INPUT_CM_MODE               0x380000
+#define        BDA7CURRENT                     0xc00000
+#define        BREGULATOR_ADJUST               0x7000000
+#define        BAD11POWERUP_ATTX               0x1
+#define        BDA10PS_ATTX                    0x10
+#define        BAD11POWERUP_ATRX               0x100
+#define        BDA10PS_ATRX                    0x1000
+#define        BCCKRX_AGC_FORMAT               0x200
+#define        BPSDFFT_SAMPLE_POINT            0xc000
+#define        BPSD_AVERAGE_NUM                0x3000
+#define        BIQPATH_CONTROL 0xc00
+#define        BPSD_FREQ                       0x3ff
+#define        BPSD_ANTENNA_PATH               0x30
+#define        BPSD_IQ_SWITCH                  0x40
+#define        BPSD_RX_TRIGGER                 0x400000
+#define        BPSD_TX_TRIGGER                 0x80000000
+#define        BPSD_SINE_TONE_SCALE            0x7f000000
+#define        BPSD_REPORT                     0xffff
+
+#define        BOFDM_TXSC                      0x30000000
+#define        BCCK_TXON                       0x1
+#define        BOFDM_TXON                      0x2
+#define        BDEBUG_PAGE                     0xfff
+#define        BDEBUG_ITEM                     0xff
+#define        BANTL                           0x10
+#define        BANT_NONHT                      0x100
+#define        BANT_HT1                        0x1000
+#define        BANT_HT2                        0x10000
+#define        BANT_HT1S1                      0x100000
+#define        BANT_NONHTS1                    0x1000000
+
+#define        BCCK_BBMODE                     0x3
+#define        BCCK_TXPOWERSAVING              0x80
+#define        BCCK_RXPOWERSAVING              0x40
+
+#define        BCCK_SIDEBAND                   0x10
+
+#define        BCCK_SCRAMBLE                   0x8
+#define        BCCK_ANTDIVERSITY               0x8000
+#define        BCCK_CARRIER_RECOVERY           0x4000
+#define        BCCK_TXRATE                     0x3000
+#define        BCCK_DCCANCEL                   0x0800
+#define        BCCK_ISICANCEL                  0x0400
+#define        BCCK_MATCH_FILTER               0x0200
+#define        BCCK_EQUALIZER                  0x0100
+#define        BCCK_PREAMBLE_DETECT            0x800000
+#define        BCCK_FAST_FALSECCA              0x400000
+#define        BCCK_CH_ESTSTART                0x300000
+#define        BCCK_CCA_COUNT                  0x080000
+#define        BCCK_CS_LIM                     0x070000
+#define        BCCK_BIST_MODE                  0x80000000
+#define        BCCK_CCAMASK                    0x40000000
+#define        BCCK_TX_DAC_PHASE               0x4
+#define        BCCK_RX_ADC_PHASE               0x20000000
+#define        BCCKR_CP_MODE                   0x0100
+#define        BCCK_TXDC_OFFSET                0xf0
+#define        BCCK_RXDC_OFFSET                0xf
+#define        BCCK_CCA_MODE                   0xc000
+#define        BCCK_FALSECS_LIM                0x3f00
+#define        BCCK_CS_RATIO                   0xc00000
+#define        BCCK_CORGBIT_SEL                0x300000
+#define        BCCK_PD_LIM                     0x0f0000
+#define        BCCK_NEWCCA                     0x80000000
+#define        BCCK_RXHP_OF_IG                 0x8000
+#define        BCCK_RXIG                       0x7f00
+#define        BCCK_LNA_POLARITY               0x800000
+#define        BCCK_RX1ST_BAIN                 0x7f0000
+#define        BCCK_RF_EXTEND                  0x20000000
+#define        BCCK_RXAGC_SATLEVEL             0x1f000000
+#define        BCCK_RXAGC_SATCOUNT             0xe0
+#define        BCCKRXRFSETTLE                  0x1f
+#define        BCCK_FIXED_RXAGC                0x8000
+#define        BCCK_ANTENNA_POLARITY           0x2000
+#define        BCCK_TXFILTER_TYPE              0x0c00
+#define        BCCK_RXAGC_REPORTTYPE           0x0300
+#define        BCCK_RXDAGC_EN                  0x80000000
+#define        BCCK_RXDAGC_PERIOD              0x20000000
+#define        BCCK_RXDAGC_SATLEVEL            0x1f000000
+#define        BCCK_TIMING_RECOVERY            0x800000
+#define        BCCK_TXC0                       0x3f0000
+#define        BCCK_TXC1                       0x3f000000
+#define        BCCK_TXC2                       0x3f
+#define        BCCK_TXC3                       0x3f00
+#define        BCCK_TXC4                       0x3f0000
+#define        BCCK_TXC5                       0x3f000000
+#define        BCCK_TXC6                       0x3f
+#define        BCCK_TXC7                       0x3f00
+#define        BCCK_DEBUGPORT                  0xff0000
+#define        BCCK_DAC_DEBUG                  0x0f000000
+#define        BCCK_FALSEALARM_ENABLE          0x8000
+#define        BCCK_FALSEALARM_READ            0x4000
+#define        BCCK_TRSSI                      0x7f
+#define        BCCK_RXAGC_REPORT               0xfe
+#define        BCCK_RXREPORT_ANTSEL            0x80000000
+#define        BCCK_RXREPORT_MFOFF             0x40000000
+#define        BCCK_RXREPORT_SQLOSS            0x20000000
+#define        BCCK_RXREPORT_PKTLOSS           0x10000000
+#define        BCCK_RXREPORT_LOCKEDBIT         0x08000000
+#define        BCCK_RXREPORT_RATEERROR         0x04000000
+#define        BCCK_RXREPORT_RXRATE            0x03000000
+#define        BCCK_RXFA_COUNTER_LOWER         0xff
+#define        BCCK_RXFA_COUNTER_UPPER         0xff000000
+#define        BCCK_RXHPAGC_START              0xe000
+#define        BCCK_RXHPAGC_FINAL              0x1c00
+#define        BCCK_RXFALSEALARM_ENABLE        0x8000
+#define        BCCK_FACOUNTER_FREEZE           0x4000
+#define        BCCK_TXPATH_SEL                 0x10000000
+#define        BCCK_DEFAULT_RXPATH             0xc000000
+#define        BCCK_OPTION_RXPATH              0x3000000
+
+#define        BNUM_OFSTF      0x3
+#define        BSHIFT_L        0xc0
+#define        BGI_TH  0xc
+#define        BRXPATH_A       0x1
+#define        BRXPATH_B       0x2
+#define        BRXPATH_C       0x4
+#define        BRXPATH_D       0x8
+#define        BTXPATH_A       0x1
+#define        BTXPATH_B       0x2
+#define        BTXPATH_C       0x4
+#define        BTXPATH_D       0x8
+#define        BTRSSI_FREQ     0x200
+#define        BADC_BACKOFF    0x3000
+#define        BDFIR_BACKOFF   0xc000
+#define        BTRSSI_LATCH_PHASE      0x10000
+#define        BRX_LDC_OFFSET  0xff
+#define        BRX_QDC_OFFSET  0xff00
+#define        BRX_DFIR_MODE   0x1800000
+#define        BRX_DCNF_TYPE   0xe000000
+#define        BRXIQIMB_A      0x3ff
+#define        BRXIQIMB_B      0xfc00
+#define        BRXIQIMB_C      0x3f0000
+#define        BRXIQIMB_D      0xffc00000
+#define        BDC_DC_NOTCH    0x60000
+#define        BRXNB_NOTCH     0x1f000000
+#define        BPD_TH  0xf
+#define        BPD_TH_OPT2     0xc000
+#define        BPWED_TH        0x700
+#define        BIFMF_WIN_L     0x800
+#define        BPD_OPTION      0x1000
+#define        BMF_WIN_L       0xe000
+#define        BBW_SEARCH_L    0x30000
+#define        BWIN_ENH_L      0xc0000
+#define        BBW_TH  0x700000
+#define        BED_TH2 0x3800000
+#define        BBW_OPTION      0x4000000
+#define        BRADIO_TH       0x18000000
+#define        BWINDOW_L       0xe0000000
+#define        BSBD_OPTION     0x1
+#define        BFRAME_TH       0x1c
+#define        BFS_OPTION      0x60
+#define        BDC_SLOPE_CHECK 0x80
+#define        BFGUARD_COUNTER_DC_L    0xe00
+#define        BFRAME_WEIGHT_SHORT     0x7000
+#define        BSUB_TUNE       0xe00000
+#define        BFRAME_DC_LENGTH        0xe000000
+#define        BSBD_START_OFFSET       0x30000000
+#define        BFRAME_TH_2     0x7
+#define        BFRAME_GI2_TH   0x38
+#define        BGI2_SYNC_EN    0x40
+#define        BSARCH_SHORT_EARLY      0x300
+#define        BSARCH_SHORT_LATE       0xc00
+#define        BSARCH_GI2_LATE 0x70000
+#define        BCFOANTSUM      0x1
+#define        BCFOACC 0x2
+#define        BCFOSTARTOFFSET 0xc
+#define        BCFOLOOPBACK    0x70
+#define        BCFOSUMWEIGHT   0x80
+#define        BDAGCENABLE     0x10000
+#define        BTXIQIMB_A      0x3ff
+#define        BTXIQIMB_b      0xfc00
+#define        BTXIQIMB_C      0x3f0000
+#define        BTXIQIMB_D      0xffc00000
+#define        BTXIDCOFFSET    0xff
+#define        BTXIQDCOFFSET   0xff00
+#define        BTXDFIRMODE     0x10000
+#define        BTXPESUDO_NOISEON       0x4000000
+#define        BTXPESUDO_NOISE_A       0xff
+#define        BTXPESUDO_NOISE_B       0xff00
+#define        BTXPESUDO_NOISE_C       0xff0000
+#define        BTXPESUDO_NOISE_D       0xff000000
+#define        BCCA_DROPOPTION 0x20000
+#define        BCCA_DROPTHRES  0xfff00000
+#define        BEDCCA_H        0xf
+#define        BEDCCA_L        0xf0
+#define        BLAMBDA_ED      0x300
+#define        BRX_INITIALGAIN 0x7f
+#define        BRX_ANTDIV_EN   0x80
+#define        BRX_AGC_ADDRESS_FOR_LNA         0x7f00
+#define        BRX_HIGHPOWER_FLOW      0x8000
+#define        BRX_AGC_FREEZE_THRES            0xc0000
+#define        BRX_FREEZESTEP_AGC1     0x300000
+#define        BRX_FREEZESTEP_AGC2     0xc00000
+#define        BRX_FREEZESTEP_AGC3     0x3000000
+#define        BRX_FREEZESTEP_AGC0     0xc000000
+#define        BRXRSSI_CMP_EN  0x10000000
+#define        BRXQUICK_AGCEN  0x20000000
+#define        BRXAGC_FREEZE_THRES_MODE        0x40000000
+#define        BRX_OVERFLOW_CHECKTYPE  0x80000000
+#define        BRX_AGCSHIFT    0x7f
+#define        BTRSW_TRI_ONLY  0x80
+#define        BPOWER_THRES    0x300
+#define        BRXAGC_EN       0x1
+#define        BRXAGC_TOGETHER_EN      0x2
+#define        BRXAGC_MIN      0x4
+#define        BRXHP_INI       0x7
+#define        BRXHP_TRLNA     0x70
+#define        BRXHP_RSSI      0x700
+#define        BRXHP_BBP1      0x7000
+#define        BRXHP_BBP2      0x70000
+#define        BRXHP_BBP3      0x700000
+#define        BRSSI_H 0x7f0000
+#define        BRSSI_GEN       0x7f000000
+#define        BRXSETTLE_TRSW  0x7
+#define        BRXSETTLE_LNA   0x38
+#define        BRXSETTLE_RSSI  0x1c0
+#define        BRXSETTLE_BBP   0xe00
+#define        BRXSETTLE_RXHP  0x7000
+#define        BRXSETTLE_ANTSW_RSSI    0x38000
+#define        BRXSETTLE_ANTSW 0xc0000
+#define        BRXPROCESS_TIME_DAGC    0x300000
+#define        BRXSETTLE_HSSI  0x400000
+#define        BRXPROCESS_TIME_BBPPW   0x800000
+#define        BRXANTENNA_POWER_SHIFT  0x3000000
+#define        BRSSI_TABLE_SELECT      0xc000000
+#define        BRXHP_FINAL     0x7000000
+#define        BRXHPSETTLE_BBP 0x7
+#define        BRXHTSETTLE_HSSI        0x8
+#define        BRXHTSETTLE_RXHP        0x70
+#define        BRXHTSETTLE_BBPPW       0x80
+#define        BRXHTSETTLE_IDLE        0x300
+#define        BRXHTSETTLE_RESERVED    0x1c00
+#define        BRXHT_RXHP_EN   0x8000
+#define        BRXAGC_FREEZE_THRES     0x30000
+#define        BRXAGC_TOGETHEREN       0x40000
+#define        BRXHTAGC_MIN    0x80000
+#define        BRXHTAGC_EN     0x100000
+#define        BRXHTDAGC_EN    0x200000
+#define        BRXHT_RXHP_BBP  0x1c00000
+#define        BRXHT_RXHP_FINAL        0xe0000000
+#define        BRXPW_RADIO_TH  0x3
+#define        BRXPW_RADIO_EN  0x4
+#define        BRXMF_HOLD      0x3800
+#define        BRXPD_DELAY_TH1 0x38
+#define        BRXPD_DELAY_TH2 0x1c0
+#define        BRXPD_DC_COUNT_MAX      0x600
+#define        BRXPD_DELAY_TH  0x8000
+#define        BRXPROCESS_DELAY        0xf0000
+#define        BRXSEARCHRANGE_GI2_EARLY        0x700000
+#define        BRXFRAME_FUARD_COUNTER_L        0x3800000
+#define        BRXSGI_GUARD_L  0xc000000
+#define        BRXSGI_SEARCH_L 0x30000000
+#define        BRXSGI_TH       0xc0000000
+#define        BDFSCNT0        0xff
+#define        BDFSCNT1        0xff00
+#define        BDFSFLAG        0xf0000
+#define        BMF_WEIGHT_SUM  0x300000
+#define        BMINIDX_TH      0x7f000000
+#define        BDAFORMAT       0x40000
+#define        BTXCH_EMU_ENABLE        0x01000000
+#define        BTRSW_ISOLATION_A       0x7f
+#define        BTRSW_ISOLATION_B       0x7f00
+#define        BTRSW_ISOLATION_C       0x7f0000
+#define        BTRSW_ISOLATION_D       0x7f000000
+#define        BEXT_LNA_GAIN   0x7c00
+
+#define        BSTBC_EN        0x4
+#define        BANTENNA_MAPPING        0x10
+#define        BNSS    0x20
+#define        BCFO_ANTSUM_ID                  0x200
+#define        BPHY_COUNTER_RESET      0x8000000
+#define        BCFO_REPORT_GET 0x4000000
+#define        BOFDM_CONTINUE_TX       0x10000000
+#define        BOFDM_SINGLE_CARRIER    0x20000000
+#define        BOFDM_SINGLE_TONE       0x40000000
+#define        BHT_DETECT      0x100
+#define        BCFOEN  0x10000
+#define        BCFOVALUE       0xfff00000
+#define        BSIGTONE_RE     0x3f
+#define        BSIGTONE_IM     0x7f00
+#define        BCOUNTER_CCA    0xffff
+#define        BCOUNTER_PARITYFAIL     0xffff0000
+#define        BCOUNTER_RATEILLEGAL    0xffff
+#define        BCOUNTER_CRC8FAIL       0xffff0000
+#define        BCOUNTER_MCSNOSUPPORT   0xffff
+#define        BCOUNTER_FASTSYNC       0xffff
+#define        BSHORTCFO       0xfff
+#define        BSHORTCFOT_LENGTH       12
+#define        BSHORTCFOF_LENGTH       11
+#define        BLONGCFO        0x7ff
+#define        BLONGCFOT_LENGTH        11
+#define        BLONGCFOF_LENGTH        11
+#define        BTAILCFO        0x1fff
+#define        BTAILCFOT_LENGTH        13
+#define        BTAILCFOF_LENGTH        12
+#define        BNOISE_EN_PWDB  0xffff
+#define        BCC_POWER_DB    0xffff0000
+#define        BMOISE_PWDB     0xffff
+#define        BPOWERMEAST_LENGTH      10
+#define        BPOWERMEASF_LENGTH      3
+#define        BRX_HT_BW       0x1
+#define        BRXSC   0x6
+#define        BRX_HT  0x8
+#define        BNB_INTF_DET_ON 0x1
+#define        BINTF_WIN_LEN_CFG       0x30
+#define        BNB_INTF_TH_CFG 0x1c0
+#define        BRFGAIN 0x3f
+#define        BTABLESEL       0x40
+#define        BTRSW   0x80
+#define        BRXSNR_A        0xff
+#define        BRXSNR_B        0xff00
+#define        BRXSNR_C        0xff0000
+#define        BRXSNR_D        0xff000000
+#define        BSNR_EVMT_LENGTH        8
+#define        BSNR_EVMF_LENGTH        1
+#define        BCSI1ST 0xff
+#define        BCSI2ND 0xff00
+#define        BRXEVM1ST       0xff0000
+#define        BRXEVM2ND       0xff000000
+#define        BSIGEVM 0xff
+#define        BPWDB   0xff00
+#define        BSGIEN  0x10000
+
+#define        BSFACTOR_QMA1   0xf
+#define        BSFACTOR_QMA2   0xf0
+#define        BSFACTOR_QMA3   0xf00
+#define        BSFACTOR_QMA4   0xf000
+#define        BSFACTOR_QMA5   0xf0000
+#define        BSFACTOR_QMA6   0xf0000
+#define        BSFACTOR_QMA7   0xf00000
+#define        BSFACTOR_QMA8   0xf000000
+#define        BSFACTOR_QMA9   0xf0000000
+#define        BCSI_SCHEME     0x100000
+
+#define        BNOISE_LVL_TOP_SET              0x3
+#define        BCHSMOOTH       0x4
+#define        BCHSMOOTH_CFG1  0x38
+#define        BCHSMOOTH_CFG2  0x1c0
+#define        BCHSMOOTH_CFG3  0xe00
+#define        BCHSMOOTH_CFG4  0x7000
+#define        BMRCMODE        0x800000
+#define        BTHEVMCFG       0x7000000
+
+#define        BLOOP_FIT_TYPE  0x1
+#define        BUPD_CFO        0x40
+#define        BUPD_CFO_OFFDATA        0x80
+#define        BADV_UPD_CFO    0x100
+#define        BADV_TIME_CTRL  0x800
+#define        BUPD_CLKO       0x1000
+#define        BFC     0x6000
+#define        BTRACKING_MODE  0x8000
+#define        BPHCMP_ENABLE   0x10000
+#define        BUPD_CLKO_LTF   0x20000
+#define        BCOM_CH_CFO     0x40000
+#define        BCSI_ESTI_MODE  0x80000
+#define        BADV_UPD_EQZ    0x100000
+#define        BUCHCFG 0x7000000
+#define        BUPDEQZ 0x8000000
+
+#define        BRX_PESUDO_NOISE_ON             0x20000000
+#define        BRX_PESUDO_NOISE_A      0xff
+#define        BRX_PESUDO_NOISE_B      0xff00
+#define        BRX_PESUDO_NOISE_C      0xff0000
+#define        BRX_PESUDO_NOISE_D      0xff000000
+#define        BRX_PESUDO_NOISESTATE_A         0xffff
+#define        BRX_PESUDO_NOISESTATE_B         0xffff0000
+#define        BRX_PESUDO_NOISESTATE_C         0xffff
+#define        BRX_PESUDO_NOISESTATE_D         0xffff0000
+
+#define        BZEBRA1_HSSIENABLE      0x8
+#define        BZEBRA1_TRXCONTROL      0xc00
+#define        BZEBRA1_TRXGAINSETTING  0x07f
+#define        BZEBRA1_RXCOUNTER       0xc00
+#define        BZEBRA1_TXCHANGEPUMP    0x38
+#define        BZEBRA1_RXCHANGEPUMP    0x7
+#define        BZEBRA1_CHANNEL_NUM     0xf80
+#define        BZEBRA1_TXLPFBW 0x400
+#define        BZEBRA1_RXLPFBW 0x600
+
+#define        BRTL8256REG_MODE_CTRL1          0x100
+#define        BRTL8256REG_MODE_CTRL0          0x40
+#define        BRTL8256REG_TXLPFBW             0x18
+#define        BRTL8256REG_RXLPFBW             0x600
+
+#define        BRTL8258_TXLPFBW        0xc
+#define        BRTL8258_RXLPFBW        0xc00
+#define        BRTL8258_RSSILPFBW      0xc0
+
+#define        BBYTE0  0x1
+#define        BBYTE1  0x2
+#define        BBYTE2  0x4
+#define        BBYTE3  0x8
+#define        BWORD0  0x3
+#define        BWORD1  0xc
+#define        BWORD   0xf
+
+#define        BENABLE 0x1
+#define        BDISABLE        0x0
+
+#define        LEFT_ANTENNA    0x0
+#define        RIGHT_ANTENNA   0x1
+
+#define        TCHECK_TXSTATUS 500
+#define        TUPDATE_RXCOUNTER       100
+
+#define        REG_UN_used_register            0x01bf
+
+/* WOL bit information */
+#define        HAL92C_WOL_PTK_UPDATE_EVENT     BIT(0)
+#define        HAL92C_WOL_GTK_UPDATE_EVENT     BIT(1)
+#define        HAL92C_WOL_DISASSOC_EVENT       BIT(2)
+#define        HAL92C_WOL_DEAUTH_EVENT         BIT(3)
+#define        HAL92C_WOL_FW_DISCONNECT_EVENT  BIT(4)
+
+#define                WOL_REASON_PTK_UPDATE           BIT(0)
+#define                WOL_REASON_GTK_UPDATE           BIT(1)
+#define                WOL_REASON_DISASSOC             BIT(2)
+#define                WOL_REASON_DEAUTH               BIT(3)
+#define                WOL_REASON_FW_DISCONNECT        BIT(4)
+
+/* 2 EFUSE_TEST (For RTL8723 partially) */
+#define EFUSE_SEL(x)                           (((x) & 0x3) << 8)
+#define EFUSE_SEL_MASK                         0x300
+#define EFUSE_WIFI_SEL_0                       0x0
+
+#define        WL_HWPDN_EN     BIT(0)  /* Enable GPIO[9] as WiFi HW PDn source*/
+#define        WL_HWPDN_SL     BIT(1)  /* WiFi HW PDn polarity control*/
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/rf.c b/drivers/net/wireless/rtlwifi/rtl8723be/rf.c
new file mode 100644 (file)
index 0000000..4862949
--- /dev/null
@@ -0,0 +1,504 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+static bool _rtl8723be_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
+
+void rtl8723be_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       switch (bandwidth) {
+       case HT_CHANNEL_WIDTH_20:
+               rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+                                            0xfffff3ff) | BIT(10) | BIT(11));
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+                             rtlphy->rfreg_chnlval[0]);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+                                            0xfffff3ff) | BIT(10));
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+                             rtlphy->rfreg_chnlval[0]);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+                        "unknown bandwidth: %#X\n", bandwidth);
+               break;
+       }
+}
+
+void rtl8723be_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+                                         u8 *ppowerlevel)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u32 tx_agc[2] = {0, 0}, tmpval;
+       bool turbo_scanoff = false;
+       u8 idx1, idx2;
+       u8 *ptr;
+       u8 direction;
+       u32 pwrtrac_value;
+
+       if (rtlefuse->eeprom_regulatory != 0)
+               turbo_scanoff = true;
+
+       if (mac->act_scanning) {
+               tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
+               tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
+
+               if (turbo_scanoff) {
+                       for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+                               tx_agc[idx1] = ppowerlevel[idx1] |
+                                              (ppowerlevel[idx1] << 8) |
+                                              (ppowerlevel[idx1] << 16) |
+                                              (ppowerlevel[idx1] << 24);
+                       }
+               }
+       } else {
+               for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+                       tx_agc[idx1] = ppowerlevel[idx1] |
+                                      (ppowerlevel[idx1] << 8) |
+                                      (ppowerlevel[idx1] << 16) |
+                                      (ppowerlevel[idx1] << 24);
+               }
+               if (rtlefuse->eeprom_regulatory == 0) {
+                       tmpval =
+                           (rtlphy->mcs_offset[0][6]) +
+                           (rtlphy->mcs_offset[0][7] << 8);
+                       tx_agc[RF90_PATH_A] += tmpval;
+
+                       tmpval = (rtlphy->mcs_offset[0][14]) +
+                                (rtlphy->mcs_offset[0][15] <<
+                                 24);
+                       tx_agc[RF90_PATH_B] += tmpval;
+               }
+       }
+       for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+               ptr = (u8 *)(&(tx_agc[idx1]));
+               for (idx2 = 0; idx2 < 4; idx2++) {
+                       if (*ptr > RF6052_MAX_TX_PWR)
+                               *ptr = RF6052_MAX_TX_PWR;
+                       ptr++;
+               }
+       }
+       rtl8723be_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+       if (direction == 1) {
+               tx_agc[0] += pwrtrac_value;
+               tx_agc[1] += pwrtrac_value;
+       } else if (direction == 2) {
+               tx_agc[0] -= pwrtrac_value;
+               tx_agc[1] -= pwrtrac_value;
+       }
+       tmpval = tx_agc[RF90_PATH_A] & 0xff;
+       rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+                RTXAGC_A_CCK1_MCS32);
+
+       tmpval = tx_agc[RF90_PATH_A] >> 8;
+
+       rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+                RTXAGC_B_CCK11_A_CCK2_11);
+
+       tmpval = tx_agc[RF90_PATH_B] >> 24;
+       rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+                RTXAGC_B_CCK11_A_CCK2_11);
+
+       tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
+       rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+                RTXAGC_B_CCK1_55_MCS32);
+}
+
+static void rtl8723be_phy_get_power_base(struct ieee80211_hw *hw,
+                                        u8 *ppowerlevel_ofdm,
+                                        u8 *ppowerlevel_bw20,
+                                        u8 *ppowerlevel_bw40,
+                                        u8 channel, u32 *ofdmbase,
+                                        u32 *mcsbase)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u32 powerbase0, powerbase1;
+       u8 i, powerlevel[2];
+
+       for (i = 0; i < 2; i++) {
+               powerbase0 = ppowerlevel_ofdm[i];
+
+               powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
+                   (powerbase0 << 8) | powerbase0;
+               *(ofdmbase + i) = powerbase0;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        " [OFDM power base index rf(%c) = 0x%x]\n",
+                        ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
+       }
+
+       for (i = 0; i < 2; i++) {
+               if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
+                       powerlevel[i] = ppowerlevel_bw20[i];
+               else
+                       powerlevel[i] = ppowerlevel_bw40[i];
+               powerbase1 = powerlevel[i];
+               powerbase1 = (powerbase1 << 24) | (powerbase1 << 16) |
+                            (powerbase1 << 8) | powerbase1;
+
+               *(mcsbase + i) = powerbase1;
+
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                       " [MCS power base index rf(%c) = 0x%x]\n",
+                       ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
+       }
+}
+
+static void txpwr_by_regulatory(struct ieee80211_hw *hw, u8 channel, u8 index,
+                               u32 *powerbase0, u32 *powerbase1,
+                               u32 *p_outwriteval)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 i, chnlgroup = 0, pwr_diff_limit[4];
+       u8 pwr_diff = 0, customer_pwr_diff;
+       u32 writeval, customer_limit, rf;
+
+       for (rf = 0; rf < 2; rf++) {
+               switch (rtlefuse->eeprom_regulatory) {
+               case 0:
+                       chnlgroup = 0;
+
+                       writeval =
+                           rtlphy->mcs_offset[chnlgroup][index + (rf ? 8 : 0)]
+                           + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                "RTK better performance, "
+                                "writeval(%c) = 0x%x\n",
+                                ((rf == 0) ? 'A' : 'B'), writeval);
+                       break;
+               case 1:
+                       if (rtlphy->pwrgroup_cnt == 1) {
+                               chnlgroup = 0;
+                       } else {
+                               if (channel < 3)
+                                       chnlgroup = 0;
+                               else if (channel < 6)
+                                       chnlgroup = 1;
+                               else if (channel < 9)
+                                       chnlgroup = 2;
+                               else if (channel < 12)
+                                       chnlgroup = 3;
+                               else if (channel < 14)
+                                       chnlgroup = 4;
+                               else if (channel == 14)
+                                       chnlgroup = 5;
+                       }
+                       writeval = rtlphy->mcs_offset[chnlgroup]
+                           [index + (rf ? 8 : 0)] + ((index < 2) ?
+                                                     powerbase0[rf] :
+                                                     powerbase1[rf]);
+
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                "Realtek regulatory, 20MHz, "
+                                "writeval(%c) = 0x%x\n",
+                                ((rf == 0) ? 'A' : 'B'), writeval);
+
+                       break;
+               case 2:
+                       writeval =
+                           ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                "Better regulatory, "
+                                "writeval(%c) = 0x%x\n",
+                                ((rf == 0) ? 'A' : 'B'), writeval);
+                       break;
+               case 3:
+                       chnlgroup = 0;
+
+                       if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                        "customer's limit, 40MHz "
+                                        "rf(%c) = 0x%x\n",
+                                        ((rf == 0) ? 'A' : 'B'),
+                                        rtlefuse->pwrgroup_ht40[rf]
+                                        [channel-1]);
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                        "customer's limit, 20MHz "
+                                        "rf(%c) = 0x%x\n",
+                                        ((rf == 0) ? 'A' : 'B'),
+                                        rtlefuse->pwrgroup_ht20[rf]
+                                        [channel-1]);
+                       }
+
+                       if (index < 2)
+                               pwr_diff =
+                                   rtlefuse->txpwr_legacyhtdiff[rf][channel-1];
+                       else if (rtlphy->current_chan_bw ==
+                                HT_CHANNEL_WIDTH_20)
+                               pwr_diff =
+                                   rtlefuse->txpwr_ht20diff[rf][channel-1];
+
+                       if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)
+                               customer_pwr_diff =
+                                       rtlefuse->pwrgroup_ht40[rf][channel-1];
+                       else
+                               customer_pwr_diff =
+                                       rtlefuse->pwrgroup_ht20[rf][channel-1];
+
+                       if (pwr_diff > customer_pwr_diff)
+                               pwr_diff = 0;
+                       else
+                               pwr_diff = customer_pwr_diff - pwr_diff;
+
+                       for (i = 0; i < 4; i++) {
+                               pwr_diff_limit[i] =
+                                   (u8)((rtlphy->mcs_offset
+                                         [chnlgroup][index + (rf ? 8 : 0)] &
+                                         (0x7f << (i * 8))) >> (i * 8));
+
+                                       if (pwr_diff_limit[i] > pwr_diff)
+                                               pwr_diff_limit[i] = pwr_diff;
+                       }
+
+                       customer_limit = (pwr_diff_limit[3] << 24) |
+                                        (pwr_diff_limit[2] << 16) |
+                                        (pwr_diff_limit[1] << 8) |
+                                        (pwr_diff_limit[0]);
+
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                               "Customer's limit rf(%c) = 0x%x\n",
+                               ((rf == 0) ? 'A' : 'B'), customer_limit);
+
+                       writeval = customer_limit + ((index < 2) ?
+                                                     powerbase0[rf] :
+                                                     powerbase1[rf]);
+
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                "Customer, writeval rf(%c)= 0x%x\n",
+                                ((rf == 0) ? 'A' : 'B'), writeval);
+                       break;
+               default:
+                       chnlgroup = 0;
+                       writeval =
+                           rtlphy->mcs_offset[chnlgroup]
+                           [index + (rf ? 8 : 0)]
+                           + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                "RTK better performance, writeval "
+                                "rf(%c) = 0x%x\n",
+                                ((rf == 0) ? 'A' : 'B'), writeval);
+                       break;
+               }
+
+               if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
+                       writeval = writeval - 0x06060606;
+               else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+                        TXHIGHPWRLEVEL_BT2)
+                       writeval = writeval - 0x0c0c0c0c;
+               *(p_outwriteval + rf) = writeval;
+       }
+}
+
+static void _rtl8723be_write_ofdm_power_reg(struct ieee80211_hw *hw,
+                                        u8 index, u32 *value)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u16 regoffset_a[6] = {
+               RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,
+               RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
+               RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
+       };
+       u16 regoffset_b[6] = {
+               RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24,
+               RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
+               RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
+       };
+       u8 i, rf, pwr_val[4];
+       u32 writeval;
+       u16 regoffset;
+
+       for (rf = 0; rf < 2; rf++) {
+               writeval = value[rf];
+               for (i = 0; i < 4; i++) {
+                       pwr_val[i] = (u8) ((writeval & (0x7f <<
+                                                       (i * 8))) >> (i * 8));
+
+                       if (pwr_val[i] > RF6052_MAX_TX_PWR)
+                               pwr_val[i] = RF6052_MAX_TX_PWR;
+               }
+               writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
+                   (pwr_val[1] << 8) | pwr_val[0];
+
+               if (rf == 0)
+                       regoffset = regoffset_a[index];
+               else
+                       regoffset = regoffset_b[index];
+               rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
+
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "Set 0x%x = %08x\n", regoffset, writeval);
+       }
+}
+
+void rtl8723be_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+                                          u8 *ppowerlevel_ofdm,
+                                          u8 *ppowerlevel_bw20,
+                                          u8 *ppowerlevel_bw40, u8 channel)
+{
+       u32 writeval[2], powerbase0[2], powerbase1[2];
+       u8 index;
+       u8 direction;
+       u32 pwrtrac_value;
+
+       rtl8723be_phy_get_power_base(hw, ppowerlevel_ofdm, ppowerlevel_bw20,
+                                    ppowerlevel_bw40, channel,
+                                    &powerbase0[0], &powerbase1[0]);
+
+       rtl8723be_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+
+       for (index = 0; index < 6; index++) {
+               txpwr_by_regulatory(hw, channel, index, &powerbase0[0],
+                                   &powerbase1[0], &writeval[0]);
+               if (direction == 1) {
+                       writeval[0] += pwrtrac_value;
+                       writeval[1] += pwrtrac_value;
+               } else if (direction == 2) {
+                       writeval[0] -= pwrtrac_value;
+                       writeval[1] -= pwrtrac_value;
+               }
+               _rtl8723be_write_ofdm_power_reg(hw, index, &writeval[0]);
+       }
+}
+
+bool rtl8723be_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       if (rtlphy->rf_type == RF_1T1R)
+               rtlphy->num_total_rfpath = 1;
+       else
+               rtlphy->num_total_rfpath = 2;
+
+       return _rtl8723be_phy_rf6052_config_parafile(hw);
+}
+
+static bool _rtl8723be_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct bb_reg_def *pphyreg;
+       u32 u4_regvalue = 0;
+       u8 rfpath;
+       bool rtstatus = true;
+
+       for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+               pphyreg = &rtlphy->phyreg_def[rfpath];
+
+               switch (rfpath) {
+               case RF90_PATH_A:
+               case RF90_PATH_C:
+                       u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+                                                   BRFSI_RFENV);
+                       break;
+               case RF90_PATH_B:
+               case RF90_PATH_D:
+                       u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+                                                   BRFSI_RFENV << 16);
+                       break;
+               }
+
+               rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);
+               udelay(1);
+
+               rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
+               udelay(1);
+
+               rtl_set_bbreg(hw, pphyreg->rfhssi_para2,
+                             B3WIREADDREAALENGTH, 0x0);
+               udelay(1);
+
+               rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);
+               udelay(1);
+
+               switch (rfpath) {
+               case RF90_PATH_A:
+                       rtstatus = rtl8723be_phy_config_rf_with_headerfile(hw,
+                                                     (enum radio_path)rfpath);
+                       break;
+               case RF90_PATH_B:
+                       rtstatus = rtl8723be_phy_config_rf_with_headerfile(hw,
+                                                     (enum radio_path)rfpath);
+                       break;
+               case RF90_PATH_C:
+                       break;
+               case RF90_PATH_D:
+                       break;
+               }
+
+               switch (rfpath) {
+               case RF90_PATH_A:
+               case RF90_PATH_C:
+                       rtl_set_bbreg(hw, pphyreg->rfintfs,
+                                     BRFSI_RFENV, u4_regvalue);
+                       break;
+               case RF90_PATH_B:
+               case RF90_PATH_D:
+                       rtl_set_bbreg(hw, pphyreg->rfintfs,
+                                     BRFSI_RFENV << 16, u4_regvalue);
+                       break;
+               }
+
+               if (!rtstatus) {
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                "Radio[%d] Fail!!", rfpath);
+                       return false;
+               }
+       }
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
+       return rtstatus;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/rf.h b/drivers/net/wireless/rtlwifi/rtl8723be/rf.h
new file mode 100644 (file)
index 0000000..a6fea10
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_RF_H__
+#define __RTL8723BE_RF_H__
+
+#define RF6052_MAX_TX_PWR              0x3F
+#define RF6052_MAX_REG                 0x3F
+
+void rtl8723be_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+                                       u8 bandwidth);
+void rtl8723be_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+                                         u8 *ppowerlevel);
+void rtl8723be_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+                                          u8 *ppowerlevel_ofdm,
+                                          u8 *ppowerlevel_bw20,
+                                          u8 *ppowerlevel_bw40,
+                                          u8 channel);
+bool rtl8723be_phy_rf6052_config(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
new file mode 100644 (file)
index 0000000..b4577eb
--- /dev/null
@@ -0,0 +1,384 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "../rtl8723com/phy_common.h"
+#include "dm.h"
+#include "hw.h"
+#include "fw.h"
+#include "../rtl8723com/fw_common.h"
+#include "sw.h"
+#include "trx.h"
+#include "led.h"
+#include "table.h"
+#include "../btcoexist/rtl_btc.h"
+
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+static void rtl8723be_init_aspm_vars(struct ieee80211_hw *hw)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       /*close ASPM for AMD defaultly */
+       rtlpci->const_amdpci_aspm = 0;
+
+       /* ASPM PS mode.
+        * 0 - Disable ASPM,
+        * 1 - Enable ASPM without Clock Req,
+        * 2 - Enable ASPM with Clock Req,
+        * 3 - Alwyas Enable ASPM with Clock Req,
+        * 4 - Always Enable ASPM without Clock Req.
+        * set defult to RTL8192CE:3 RTL8192E:2
+        */
+       rtlpci->const_pci_aspm = 3;
+
+       /*Setting for PCI-E device */
+       rtlpci->const_devicepci_aspm_setting = 0x03;
+
+       /*Setting for PCI-E bridge */
+       rtlpci->const_hostpci_aspm_setting = 0x02;
+
+       /* In Hw/Sw Radio Off situation.
+        * 0 - Default,
+        * 1 - From ASPM setting without low Mac Pwr,
+        * 2 - From ASPM setting with low Mac Pwr,
+        * 3 - Bus D3
+        * set default to RTL8192CE:0 RTL8192SE:2
+        */
+       rtlpci->const_hwsw_rfoff_d3 = 0;
+
+       /* This setting works for those device with
+        * backdoor ASPM setting such as EPHY setting.
+        * 0 - Not support ASPM,
+        * 1 - Support ASPM,
+        * 2 - According to chipset.
+        */
+       rtlpci->const_support_pciaspm = 1;
+}
+
+int rtl8723be_init_sw_vars(struct ieee80211_hw *hw)
+{
+       int err = 0;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+       rtl8723be_bt_reg_init(hw);
+       rtlpci->msi_support = true;
+       rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
+
+       rtlpriv->dm.dm_initialgain_enable = 1;
+       rtlpriv->dm.dm_flag = 0;
+       rtlpriv->dm.disable_framebursting = 0;
+       rtlpriv->dm.thermalvalue = 0;
+       rtlpci->transmit_config = CFENDFORM | BIT(15) | BIT(24) | BIT(25);
+
+       mac->ht_enable = true;
+
+       /* compatible 5G band 88ce just 2.4G band & smsp */
+       rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+       rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+       rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+       rtlpci->receive_config = (RCR_APPFCS            |
+                                 RCR_APP_MIC           |
+                                 RCR_APP_ICV           |
+                                 RCR_APP_PHYST_RXFF    |
+                                 RCR_HTC_LOC_CTRL      |
+                                 RCR_AMF               |
+                                 RCR_ACF               |
+                                 RCR_ADF               |
+                                 RCR_AICV              |
+                                 RCR_AB                |
+                                 RCR_AM                |
+                                 RCR_APM               |
+                                 0);
+
+       rtlpci->irq_mask[0] = (u32) (IMR_PSTIMEOUT      |
+                                    IMR_HSISR_IND_ON_INT       |
+                                    IMR_C2HCMD         |
+                                    IMR_HIGHDOK        |
+                                    IMR_MGNTDOK        |
+                                    IMR_BKDOK          |
+                                    IMR_BEDOK          |
+                                    IMR_VIDOK          |
+                                    IMR_VODOK          |
+                                    IMR_RDU            |
+                                    IMR_ROK            |
+                                    0);
+
+       rtlpci->irq_mask[1] = (u32)(IMR_RXFOVW | 0);
+
+       /* for debug level */
+       rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
+       /* for LPS & IPS */
+       rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+       rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+       rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+       rtlpriv->psc.reg_fwctrl_lps = 3;
+       rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+       /* for ASPM, you can close aspm through
+        * set const_support_pciaspm = 0
+        */
+       rtl8723be_init_aspm_vars(hw);
+
+       if (rtlpriv->psc.reg_fwctrl_lps == 1)
+               rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+       else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+               rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+       else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+               rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+       /* for firmware buf */
+       rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
+       if (!rtlpriv->rtlhal.pfirmware) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Can't alloc buffer for fw.\n");
+               return 1;
+       }
+
+       rtlpriv->max_fw_size = 0x8000;
+       pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
+       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+                                     rtlpriv->io.dev, GFP_KERNEL, hw,
+                                     rtl_fw_cb);
+       if (err) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Failed to request firmware!\n");
+               return 1;
+       }
+       return 0;
+}
+
+void rtl8723be_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->cfg->ops->get_btc_status())
+               rtlpriv->btcoexist.btc_ops->btc_halt_notify();
+       if (rtlpriv->rtlhal.pfirmware) {
+               vfree(rtlpriv->rtlhal.pfirmware);
+               rtlpriv->rtlhal.pfirmware = NULL;
+       }
+}
+
+/* get bt coexist status */
+bool rtl8723be_get_btc_status(void)
+{
+       return true;
+}
+
+static bool is_fw_header(struct rtl92c_firmware_header *hdr)
+{
+       return (hdr->signature & 0xfff0) == 0x5300;
+}
+
+static struct rtl_hal_ops rtl8723be_hal_ops = {
+       .init_sw_vars = rtl8723be_init_sw_vars,
+       .deinit_sw_vars = rtl8723be_deinit_sw_vars,
+       .read_eeprom_info = rtl8723be_read_eeprom_info,
+       .interrupt_recognized = rtl8723be_interrupt_recognized,
+       .hw_init = rtl8723be_hw_init,
+       .hw_disable = rtl8723be_card_disable,
+       .hw_suspend = rtl8723be_suspend,
+       .hw_resume = rtl8723be_resume,
+       .enable_interrupt = rtl8723be_enable_interrupt,
+       .disable_interrupt = rtl8723be_disable_interrupt,
+       .set_network_type = rtl8723be_set_network_type,
+       .set_chk_bssid = rtl8723be_set_check_bssid,
+       .set_qos = rtl8723be_set_qos,
+       .set_bcn_reg = rtl8723be_set_beacon_related_registers,
+       .set_bcn_intv = rtl8723be_set_beacon_interval,
+       .update_interrupt_mask = rtl8723be_update_interrupt_mask,
+       .get_hw_reg = rtl8723be_get_hw_reg,
+       .set_hw_reg = rtl8723be_set_hw_reg,
+       .update_rate_tbl = rtl8723be_update_hal_rate_tbl,
+       .fill_tx_desc = rtl8723be_tx_fill_desc,
+       .fill_tx_cmddesc = rtl8723be_tx_fill_cmddesc,
+       .query_rx_desc = rtl8723be_rx_query_desc,
+       .set_channel_access = rtl8723be_update_channel_access_setting,
+       .radio_onoff_checking = rtl8723be_gpio_radio_on_off_checking,
+       .set_bw_mode = rtl8723be_phy_set_bw_mode,
+       .switch_channel = rtl8723be_phy_sw_chnl,
+       .dm_watchdog = rtl8723be_dm_watchdog,
+       .scan_operation_backup = rtl8723be_phy_scan_operation_backup,
+       .set_rf_power_state = rtl8723be_phy_set_rf_power_state,
+       .led_control = rtl8723be_led_control,
+       .set_desc = rtl8723be_set_desc,
+       .get_desc = rtl8723be_get_desc,
+       .is_tx_desc_closed = rtl8723be_is_tx_desc_closed,
+       .tx_polling = rtl8723be_tx_polling,
+       .enable_hw_sec = rtl8723be_enable_hw_security_config,
+       .set_key = rtl8723be_set_key,
+       .init_sw_leds = rtl8723be_init_sw_leds,
+       .get_bbreg = rtl8723_phy_query_bb_reg,
+       .set_bbreg = rtl8723_phy_set_bb_reg,
+       .get_rfreg = rtl8723be_phy_query_rf_reg,
+       .set_rfreg = rtl8723be_phy_set_rf_reg,
+       .fill_h2c_cmd = rtl8723be_fill_h2c_cmd,
+       .get_btc_status = rtl8723be_get_btc_status,
+       .is_fw_header = is_fw_header,
+};
+
+static struct rtl_mod_params rtl8723be_mod_params = {
+       .sw_crypto = false,
+       .inactiveps = true,
+       .swctrl_lps = false,
+       .fwctrl_lps = true,
+       .debug = DBG_EMERG,
+};
+
+static struct rtl_hal_cfg rtl8723be_hal_cfg = {
+       .bar_id = 2,
+       .write_readback = true,
+       .name = "rtl8723be_pci",
+       .fw_name = "rtlwifi/rtl8723befw.bin",
+       .ops = &rtl8723be_hal_ops,
+       .mod_params = &rtl8723be_mod_params,
+       .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+       .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+       .maps[SYS_CLK] = REG_SYS_CLKR,
+       .maps[MAC_RCR_AM] = AM,
+       .maps[MAC_RCR_AB] = AB,
+       .maps[MAC_RCR_ACRC32] = ACRC32,
+       .maps[MAC_RCR_ACF] = ACF,
+       .maps[MAC_RCR_AAP] = AAP,
+
+       .maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS,
+
+       .maps[EFUSE_TEST] = REG_EFUSE_TEST,
+       .maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+       .maps[EFUSE_CLK] = 0,
+       .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+       .maps[EFUSE_PWC_EV12V] = PWC_EV12V,
+       .maps[EFUSE_FEN_ELDR] = FEN_ELDR,
+       .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
+       .maps[EFUSE_ANA8M] = ANA8M,
+       .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+       .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+       .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+       .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
+
+       .maps[RWCAM] = REG_CAMCMD,
+       .maps[WCAMI] = REG_CAMWRITE,
+       .maps[RCAMO] = REG_CAMREAD,
+       .maps[CAMDBG] = REG_CAMDBG,
+       .maps[SECR] = REG_SECCFG,
+       .maps[SEC_CAM_NONE] = CAM_NONE,
+       .maps[SEC_CAM_WEP40] = CAM_WEP40,
+       .maps[SEC_CAM_TKIP] = CAM_TKIP,
+       .maps[SEC_CAM_AES] = CAM_AES,
+       .maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+       .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+       .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+       .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+       .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+       .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+       .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+       .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+       .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+       .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+       .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+       .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+       .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+       .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+
+       .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
+       .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
+       .maps[RTL_IMR_BCNINT] = IMR_BCNDMAINT0,
+       .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
+       .maps[RTL_IMR_RDU] = IMR_RDU,
+       .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
+       .maps[RTL_IMR_BDOK] = IMR_BCNDOK0,
+       .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK,
+       .maps[RTL_IMR_TBDER] = IMR_TBDER,
+       .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK,
+       .maps[RTL_IMR_TBDOK] = IMR_TBDOK,
+       .maps[RTL_IMR_BKDOK] = IMR_BKDOK,
+       .maps[RTL_IMR_BEDOK] = IMR_BEDOK,
+       .maps[RTL_IMR_VIDOK] = IMR_VIDOK,
+       .maps[RTL_IMR_VODOK] = IMR_VODOK,
+       .maps[RTL_IMR_ROK] = IMR_ROK,
+       .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER),
+
+       .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
+       .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
+       .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
+       .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
+       .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
+       .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
+       .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
+       .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
+       .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
+       .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
+       .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
+       .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
+
+       .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
+       .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(rtl8723be_pci_id) = {
+       {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xb723, rtl8723be_hal_cfg)},
+       {},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl8723be_pci_id);
+
+MODULE_AUTHOR("PageHe  <page_he@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8723BE 802.11n PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8723befw.bin");
+
+module_param_named(swenc, rtl8723be_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl8723be_mod_params.debug, int, 0444);
+module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444);
+MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
+MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
+MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+
+static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
+
+static struct pci_driver rtl8723be_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = rtl8723be_pci_id,
+       .probe = rtl_pci_probe,
+       .remove = rtl_pci_disconnect,
+
+       .driver.pm = &rtlwifi_pm_ops,
+};
+
+module_pci_driver(rtl8723be_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.h b/drivers/net/wireless/rtlwifi/rtl8723be/sw.h
new file mode 100644 (file)
index 0000000..a7b25e7
--- /dev/null
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_SW_H__
+#define __RTL8723BE_SW_H__
+
+int rtl8723be_init_sw_vars(struct ieee80211_hw *hw);
+void rtl8723be_deinit_sw_vars(struct ieee80211_hw *hw);
+void rtl8723be_init_var_map(struct ieee80211_hw *hw);
+bool rtl8723be_get_btc_status(void);
+
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/table.c b/drivers/net/wireless/rtlwifi/rtl8723be/table.c
new file mode 100644 (file)
index 0000000..4b283cd
--- /dev/null
@@ -0,0 +1,572 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on  2010/ 5/18,  1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "table.h"
+u32 RTL8723BEPHY_REG_1TARRAY[] = {
+       0x800, 0x80040000,
+       0x804, 0x00000003,
+       0x808, 0x0000FC00,
+       0x80C, 0x0000000A,
+       0x810, 0x10001331,
+       0x814, 0x020C3D10,
+       0x818, 0x02200385,
+       0x81C, 0x00000000,
+       0x820, 0x01000100,
+       0x824, 0x00390204,
+       0x828, 0x00000000,
+       0x82C, 0x00000000,
+       0x830, 0x00000000,
+       0x834, 0x00000000,
+       0x838, 0x00000000,
+       0x83C, 0x00000000,
+       0x840, 0x00010000,
+       0x844, 0x00000000,
+       0x848, 0x00000000,
+       0x84C, 0x00000000,
+       0x850, 0x00000000,
+       0x854, 0x00000000,
+       0x858, 0x569A11A9,
+       0x85C, 0x01000014,
+       0x860, 0x66F60110,
+       0x864, 0x061F0649,
+       0x868, 0x00000000,
+       0x86C, 0x27272700,
+       0x870, 0x07000760,
+       0x874, 0x25004000,
+       0x878, 0x00000808,
+       0x87C, 0x00000000,
+       0x880, 0xB0000C1C,
+       0x884, 0x00000001,
+       0x888, 0x00000000,
+       0x88C, 0xCCC000C0,
+       0x890, 0x00000800,
+       0x894, 0xFFFFFFFE,
+       0x898, 0x40302010,
+       0x89C, 0x00706050,
+       0x900, 0x00000000,
+       0x904, 0x00000023,
+       0x908, 0x00000000,
+       0x90C, 0x81121111,
+       0x910, 0x00000002,
+       0x914, 0x00000201,
+       0x948, 0x00000000,
+       0xA00, 0x00D047C8,
+       0xA04, 0x80FF000C,
+       0xA08, 0x8C838300,
+       0xA0C, 0x2E7F120F,
+       0xA10, 0x9500BB78,
+       0xA14, 0x1114D028,
+       0xA18, 0x00881117,
+       0xA1C, 0x89140F00,
+       0xA20, 0x1A1B0000,
+       0xA24, 0x090E1317,
+       0xA28, 0x00000204,
+       0xA2C, 0x00D30000,
+       0xA70, 0x101FBF00,
+       0xA74, 0x00000007,
+       0xA78, 0x00000900,
+       0xA7C, 0x225B0606,
+       0xA80, 0x21806490,
+       0xB2C, 0x00000000,
+       0xC00, 0x48071D40,
+       0xC04, 0x03A05611,
+       0xC08, 0x000000E4,
+       0xC0C, 0x6C6C6C6C,
+       0xC10, 0x08800000,
+       0xC14, 0x40000100,
+       0xC18, 0x08800000,
+       0xC1C, 0x40000100,
+       0xC20, 0x00000000,
+       0xC24, 0x00000000,
+       0xC28, 0x00000000,
+       0xC2C, 0x00000000,
+       0xC30, 0x69E9AC44,
+       0xC34, 0x469652AF,
+       0xC38, 0x49795994,
+       0xC3C, 0x0A97971C,
+       0xC40, 0x1F7C403F,
+       0xC44, 0x000100B7,
+       0xC48, 0xEC020107,
+       0xC4C, 0x007F037F,
+       0xC50, 0x69553420,
+       0xC54, 0x43BC0094,
+       0xC58, 0x00023169,
+       0xC5C, 0x00250492,
+       0xC60, 0x00000000,
+       0xC64, 0x7112848B,
+       0xC68, 0x47C00BFF,
+       0xC6C, 0x00000036,
+       0xC70, 0x2C7F000D,
+       0xC74, 0x020610DB,
+       0xC78, 0x0000001F,
+       0xC7C, 0x00B91612,
+       0xC80, 0x390000E4,
+       0xC84, 0x20F60000,
+       0xC88, 0x40000100,
+       0xC8C, 0x20200000,
+       0xC90, 0x00020E1A,
+       0xC94, 0x00000000,
+       0xC98, 0x00020E1A,
+       0xC9C, 0x00007F7F,
+       0xCA0, 0x00000000,
+       0xCA4, 0x000300A0,
+       0xCA8, 0x00000000,
+       0xCAC, 0x00000000,
+       0xCB0, 0x00000000,
+       0xCB4, 0x00000000,
+       0xCB8, 0x00000000,
+       0xCBC, 0x28000000,
+       0xCC0, 0x00000000,
+       0xCC4, 0x00000000,
+       0xCC8, 0x00000000,
+       0xCCC, 0x00000000,
+       0xCD0, 0x00000000,
+       0xCD4, 0x00000000,
+       0xCD8, 0x64B22427,
+       0xCDC, 0x00766932,
+       0xCE0, 0x00222222,
+       0xCE4, 0x00000000,
+       0xCE8, 0x37644302,
+       0xCEC, 0x2F97D40C,
+       0xD00, 0x00000740,
+       0xD04, 0x40020401,
+       0xD08, 0x0000907F,
+       0xD0C, 0x20010201,
+       0xD10, 0xA0633333,
+       0xD14, 0x3333BC53,
+       0xD18, 0x7A8F5B6F,
+       0xD2C, 0xCC979975,
+       0xD30, 0x00000000,
+       0xD34, 0x80608000,
+       0xD38, 0x00000000,
+       0xD3C, 0x00127353,
+       0xD40, 0x00000000,
+       0xD44, 0x00000000,
+       0xD48, 0x00000000,
+       0xD4C, 0x00000000,
+       0xD50, 0x6437140A,
+       0xD54, 0x00000000,
+       0xD58, 0x00000282,
+       0xD5C, 0x30032064,
+       0xD60, 0x4653DE68,
+       0xD64, 0x04518A3C,
+       0xD68, 0x00002101,
+       0xD6C, 0x2A201C16,
+       0xD70, 0x1812362E,
+       0xD74, 0x322C2220,
+       0xD78, 0x000E3C24,
+       0xE00, 0x2D2D2D2D,
+       0xE04, 0x2D2D2D2D,
+       0xE08, 0x0390272D,
+       0xE10, 0x2D2D2D2D,
+       0xE14, 0x2D2D2D2D,
+       0xE18, 0x2D2D2D2D,
+       0xE1C, 0x2D2D2D2D,
+       0xE28, 0x00000000,
+       0xE30, 0x1000DC1F,
+       0xE34, 0x10008C1F,
+       0xE38, 0x02140102,
+       0xE3C, 0x681604C2,
+       0xE40, 0x01007C00,
+       0xE44, 0x01004800,
+       0xE48, 0xFB000000,
+       0xE4C, 0x000028D1,
+       0xE50, 0x1000DC1F,
+       0xE54, 0x10008C1F,
+       0xE58, 0x02140102,
+       0xE5C, 0x28160D05,
+       0xE60, 0x00000008,
+       0xE68, 0x001B2556,
+       0xE6C, 0x00C00096,
+       0xE70, 0x00C00096,
+       0xE74, 0x01000056,
+       0xE78, 0x01000014,
+       0xE7C, 0x01000056,
+       0xE80, 0x01000014,
+       0xE84, 0x00C00096,
+       0xE88, 0x01000056,
+       0xE8C, 0x00C00096,
+       0xED0, 0x00C00096,
+       0xED4, 0x00C00096,
+       0xED8, 0x00C00096,
+       0xEDC, 0x000000D6,
+       0xEE0, 0x000000D6,
+       0xEEC, 0x01C00016,
+       0xF14, 0x00000003,
+       0xF4C, 0x00000000,
+       0xF00, 0x00000300,
+       0x820, 0x01000100,
+       0x800, 0x83040000,
+};
+
+u32 RTL8723BEPHY_REG_ARRAY_PG[] = {
+       0, 0, 0, 0x00000e08, 0x0000ff00, 0x00004000,
+       0, 0, 0, 0x0000086c, 0xffffff00, 0x34363800,
+       0, 0, 0, 0x00000e00, 0xffffffff, 0x42444646,
+       0, 0, 0, 0x00000e04, 0xffffffff, 0x30343840,
+       0, 0, 0, 0x00000e10, 0xffffffff, 0x38404244,
+       0, 0, 0, 0x00000e14, 0xffffffff, 0x26303436
+};
+
+u32 RTL8723BE_RADIOA_1TARRAY[] = {
+       0x000, 0x00010000,
+       0x0B0, 0x000DFFE0,
+       0x0FE, 0x00000000,
+       0x0FE, 0x00000000,
+       0x0FE, 0x00000000,
+       0x0B1, 0x00000018,
+       0x0FE, 0x00000000,
+       0x0FE, 0x00000000,
+       0x0FE, 0x00000000,
+       0x0B2, 0x00084C00,
+       0x0B5, 0x0000D2CC,
+       0x0B6, 0x000925AA,
+       0x0B7, 0x00000010,
+       0x0B8, 0x0000907F,
+       0x05C, 0x00000002,
+       0x07C, 0x00000002,
+       0x07E, 0x00000005,
+       0x08B, 0x0006FC00,
+       0x0B0, 0x000FF9F0,
+       0x01C, 0x000739D2,
+       0x01E, 0x00000000,
+       0x0DF, 0x00000780,
+       0x050, 0x00067435,
+       0x051, 0x0006B04E,
+       0x052, 0x000007D2,
+       0x053, 0x00000000,
+       0x054, 0x00050400,
+       0x055, 0x0004026E,
+       0x0DD, 0x0000004C,
+       0x070, 0x00067435,
+       0x071, 0x0006B04E,
+       0x072, 0x000007D2,
+       0x073, 0x00000000,
+       0x074, 0x00050400,
+       0x075, 0x0004026E,
+       0x0EF, 0x00000100,
+       0x034, 0x0000ADD7,
+       0x035, 0x00005C00,
+       0x034, 0x00009DD4,
+       0x035, 0x00005000,
+       0x034, 0x00008DD1,
+       0x035, 0x00004400,
+       0x034, 0x00007DCE,
+       0x035, 0x00003800,
+       0x034, 0x00006CD1,
+       0x035, 0x00004400,
+       0x034, 0x00005CCE,
+       0x035, 0x00003800,
+       0x034, 0x000048CE,
+       0x035, 0x00004400,
+       0x034, 0x000034CE,
+       0x035, 0x00003800,
+       0x034, 0x00002451,
+       0x035, 0x00004400,
+       0x034, 0x0000144E,
+       0x035, 0x00003800,
+       0x034, 0x00000051,
+       0x035, 0x00004400,
+       0x0EF, 0x00000000,
+       0x0EF, 0x00000100,
+       0x0ED, 0x00000010,
+       0x044, 0x0000ADD7,
+       0x044, 0x00009DD4,
+       0x044, 0x00008DD1,
+       0x044, 0x00007DCE,
+       0x044, 0x00006CC1,
+       0x044, 0x00005CCE,
+       0x044, 0x000044D1,
+       0x044, 0x000034CE,
+       0x044, 0x00002451,
+       0x044, 0x0000144E,
+       0x044, 0x00000051,
+       0x0EF, 0x00000000,
+       0x0ED, 0x00000000,
+       0x0EF, 0x00002000,
+       0x03B, 0x000380EF,
+       0x03B, 0x000302FE,
+       0x03B, 0x00028CE6,
+       0x03B, 0x000200BC,
+       0x03B, 0x000188A5,
+       0x03B, 0x00010FBC,
+       0x03B, 0x00008F71,
+       0x03B, 0x00000900,
+       0x0EF, 0x00000000,
+       0x0ED, 0x00000001,
+       0x040, 0x000380EF,
+       0x040, 0x000302FE,
+       0x040, 0x00028CE6,
+       0x040, 0x000200BC,
+       0x040, 0x000188A5,
+       0x040, 0x00010FBC,
+       0x040, 0x00008F71,
+       0x040, 0x00000900,
+       0x0ED, 0x00000000,
+       0x082, 0x00080000,
+       0x083, 0x00008000,
+       0x084, 0x00048D80,
+       0x085, 0x00068000,
+       0x0A2, 0x00080000,
+       0x0A3, 0x00008000,
+       0x0A4, 0x00048D80,
+       0x0A5, 0x00068000,
+       0x000, 0x00033D80,
+};
+
+u32 RTL8723BEMAC_1T_ARRAY[] = {
+       0x02F, 0x00000030,
+       0x035, 0x00000000,
+       0x428, 0x0000000A,
+       0x429, 0x00000010,
+       0x430, 0x00000000,
+       0x431, 0x00000000,
+       0x432, 0x00000000,
+       0x433, 0x00000001,
+       0x434, 0x00000004,
+       0x435, 0x00000005,
+       0x436, 0x00000007,
+       0x437, 0x00000008,
+       0x43C, 0x00000004,
+       0x43D, 0x00000005,
+       0x43E, 0x00000007,
+       0x43F, 0x00000008,
+       0x440, 0x0000005D,
+       0x441, 0x00000001,
+       0x442, 0x00000000,
+       0x444, 0x00000010,
+       0x445, 0x00000000,
+       0x446, 0x00000000,
+       0x447, 0x00000000,
+       0x448, 0x00000000,
+       0x449, 0x000000F0,
+       0x44A, 0x0000000F,
+       0x44B, 0x0000003E,
+       0x44C, 0x00000010,
+       0x44D, 0x00000000,
+       0x44E, 0x00000000,
+       0x44F, 0x00000000,
+       0x450, 0x00000000,
+       0x451, 0x000000F0,
+       0x452, 0x0000000F,
+       0x453, 0x00000000,
+       0x456, 0x0000005E,
+       0x460, 0x00000066,
+       0x461, 0x00000066,
+       0x4C8, 0x000000FF,
+       0x4C9, 0x00000008,
+       0x4CC, 0x000000FF,
+       0x4CD, 0x000000FF,
+       0x4CE, 0x00000001,
+       0x500, 0x00000026,
+       0x501, 0x000000A2,
+       0x502, 0x0000002F,
+       0x503, 0x00000000,
+       0x504, 0x00000028,
+       0x505, 0x000000A3,
+       0x506, 0x0000005E,
+       0x507, 0x00000000,
+       0x508, 0x0000002B,
+       0x509, 0x000000A4,
+       0x50A, 0x0000005E,
+       0x50B, 0x00000000,
+       0x50C, 0x0000004F,
+       0x50D, 0x000000A4,
+       0x50E, 0x00000000,
+       0x50F, 0x00000000,
+       0x512, 0x0000001C,
+       0x514, 0x0000000A,
+       0x516, 0x0000000A,
+       0x525, 0x0000004F,
+       0x550, 0x00000010,
+       0x551, 0x00000010,
+       0x559, 0x00000002,
+       0x55C, 0x00000050,
+       0x55D, 0x000000FF,
+       0x605, 0x00000030,
+       0x608, 0x0000000E,
+       0x609, 0x0000002A,
+       0x620, 0x000000FF,
+       0x621, 0x000000FF,
+       0x622, 0x000000FF,
+       0x623, 0x000000FF,
+       0x624, 0x000000FF,
+       0x625, 0x000000FF,
+       0x626, 0x000000FF,
+       0x627, 0x000000FF,
+       0x638, 0x00000050,
+       0x63C, 0x0000000A,
+       0x63D, 0x0000000A,
+       0x63E, 0x0000000E,
+       0x63F, 0x0000000E,
+       0x640, 0x00000040,
+       0x642, 0x00000040,
+       0x643, 0x00000000,
+       0x652, 0x000000C8,
+       0x66E, 0x00000005,
+       0x700, 0x00000021,
+       0x701, 0x00000043,
+       0x702, 0x00000065,
+       0x703, 0x00000087,
+       0x708, 0x00000021,
+       0x709, 0x00000043,
+       0x70A, 0x00000065,
+       0x70B, 0x00000087,
+};
+
+u32 RTL8723BEAGCTAB_1TARRAY[] = {
+       0xC78, 0xFD000001,
+       0xC78, 0xFC010001,
+       0xC78, 0xFB020001,
+       0xC78, 0xFA030001,
+       0xC78, 0xF9040001,
+       0xC78, 0xF8050001,
+       0xC78, 0xF7060001,
+       0xC78, 0xF6070001,
+       0xC78, 0xF5080001,
+       0xC78, 0xF4090001,
+       0xC78, 0xF30A0001,
+       0xC78, 0xF20B0001,
+       0xC78, 0xF10C0001,
+       0xC78, 0xF00D0001,
+       0xC78, 0xEF0E0001,
+       0xC78, 0xEE0F0001,
+       0xC78, 0xED100001,
+       0xC78, 0xEC110001,
+       0xC78, 0xEB120001,
+       0xC78, 0xEA130001,
+       0xC78, 0xE9140001,
+       0xC78, 0xE8150001,
+       0xC78, 0xE7160001,
+       0xC78, 0xAA170001,
+       0xC78, 0xA9180001,
+       0xC78, 0xA8190001,
+       0xC78, 0xA71A0001,
+       0xC78, 0xA61B0001,
+       0xC78, 0xA51C0001,
+       0xC78, 0xA41D0001,
+       0xC78, 0xA31E0001,
+       0xC78, 0x671F0001,
+       0xC78, 0x66200001,
+       0xC78, 0x65210001,
+       0xC78, 0x64220001,
+       0xC78, 0x63230001,
+       0xC78, 0x62240001,
+       0xC78, 0x61250001,
+       0xC78, 0x47260001,
+       0xC78, 0x46270001,
+       0xC78, 0x45280001,
+       0xC78, 0x44290001,
+       0xC78, 0x432A0001,
+       0xC78, 0x422B0001,
+       0xC78, 0x292C0001,
+       0xC78, 0x282D0001,
+       0xC78, 0x272E0001,
+       0xC78, 0x262F0001,
+       0xC78, 0x25300001,
+       0xC78, 0x24310001,
+       0xC78, 0x09320001,
+       0xC78, 0x08330001,
+       0xC78, 0x07340001,
+       0xC78, 0x06350001,
+       0xC78, 0x05360001,
+       0xC78, 0x04370001,
+       0xC78, 0x03380001,
+       0xC78, 0x02390001,
+       0xC78, 0x013A0001,
+       0xC78, 0x003B0001,
+       0xC78, 0x003C0001,
+       0xC78, 0x003D0001,
+       0xC78, 0x003E0001,
+       0xC78, 0x003F0001,
+       0xC78, 0xFC400001,
+       0xC78, 0xFB410001,
+       0xC78, 0xFA420001,
+       0xC78, 0xF9430001,
+       0xC78, 0xF8440001,
+       0xC78, 0xF7450001,
+       0xC78, 0xF6460001,
+       0xC78, 0xF5470001,
+       0xC78, 0xF4480001,
+       0xC78, 0xF3490001,
+       0xC78, 0xF24A0001,
+       0xC78, 0xF14B0001,
+       0xC78, 0xF04C0001,
+       0xC78, 0xEF4D0001,
+       0xC78, 0xEE4E0001,
+       0xC78, 0xED4F0001,
+       0xC78, 0xEC500001,
+       0xC78, 0xEB510001,
+       0xC78, 0xEA520001,
+       0xC78, 0xE9530001,
+       0xC78, 0xE8540001,
+       0xC78, 0xE7550001,
+       0xC78, 0xE6560001,
+       0xC78, 0xE5570001,
+       0xC78, 0xAA580001,
+       0xC78, 0xA9590001,
+       0xC78, 0xA85A0001,
+       0xC78, 0xA75B0001,
+       0xC78, 0xA65C0001,
+       0xC78, 0xA55D0001,
+       0xC78, 0xA45E0001,
+       0xC78, 0x675F0001,
+       0xC78, 0x66600001,
+       0xC78, 0x65610001,
+       0xC78, 0x64620001,
+       0xC78, 0x63630001,
+       0xC78, 0x62640001,
+       0xC78, 0x61650001,
+       0xC78, 0x47660001,
+       0xC78, 0x46670001,
+       0xC78, 0x45680001,
+       0xC78, 0x44690001,
+       0xC78, 0x436A0001,
+       0xC78, 0x426B0001,
+       0xC78, 0x296C0001,
+       0xC78, 0x286D0001,
+       0xC78, 0x276E0001,
+       0xC78, 0x266F0001,
+       0xC78, 0x25700001,
+       0xC78, 0x24710001,
+       0xC78, 0x09720001,
+       0xC78, 0x08730001,
+       0xC78, 0x07740001,
+       0xC78, 0x06750001,
+       0xC78, 0x05760001,
+       0xC78, 0x04770001,
+       0xC78, 0x03780001,
+       0xC78, 0x02790001,
+       0xC78, 0x017A0001,
+       0xC78, 0x007B0001,
+       0xC78, 0x007C0001,
+       0xC78, 0x007D0001,
+       0xC78, 0x007E0001,
+       0xC78, 0x007F0001,
+       0xC50, 0x69553422,
+       0xC50, 0x69553420,
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/table.h b/drivers/net/wireless/rtlwifi/rtl8723be/table.h
new file mode 100644 (file)
index 0000000..932760a
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on  2010/ 5/18,  1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_TABLE__H_
+#define __RTL8723BE_TABLE__H_
+
+#include <linux/types.h>
+#define  RTL8723BEPHY_REG_1TARRAYLEN   388
+extern u32 RTL8723BEPHY_REG_1TARRAY[];
+#define RTL8723BEPHY_REG_ARRAY_PGLEN   36
+extern u32 RTL8723BEPHY_REG_ARRAY_PG[];
+#define        RTL8723BE_RADIOA_1TARRAYLEN     206
+extern u32 RTL8723BE_RADIOA_1TARRAY[];
+#define RTL8723BEMAC_1T_ARRAYLEN       194
+extern u32 RTL8723BEMAC_1T_ARRAY[];
+#define RTL8723BEAGCTAB_1TARRAYLEN     260
+extern u32 RTL8723BEAGCTAB_1TARRAY[];
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c
new file mode 100644 (file)
index 0000000..74a75dc
--- /dev/null
@@ -0,0 +1,960 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "../stats.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "trx.h"
+#include "led.h"
+#include "dm.h"
+#include "phy.h"
+
+static u8 _rtl8723be_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
+{
+       __le16 fc = rtl_get_fc(skb);
+
+       if (unlikely(ieee80211_is_beacon(fc)))
+               return QSLT_BEACON;
+       if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
+               return QSLT_MGNT;
+
+       return skb->priority;
+}
+
+/* mac80211's rate_idx is like this:
+ *
+ * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
+ *
+ * B/G rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ *
+ * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
+ * A rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ */
+static int _rtl8723be_rate_mapping(struct ieee80211_hw *hw,
+                                  bool isht, u8 desc_rate)
+{
+       int rate_idx;
+
+       if (!isht) {
+               if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
+                       switch (desc_rate) {
+                       case DESC92C_RATE1M:
+                               rate_idx = 0;
+                               break;
+                       case DESC92C_RATE2M:
+                               rate_idx = 1;
+                               break;
+                       case DESC92C_RATE5_5M:
+                               rate_idx = 2;
+                               break;
+                       case DESC92C_RATE11M:
+                               rate_idx = 3;
+                               break;
+                       case DESC92C_RATE6M:
+                               rate_idx = 4;
+                               break;
+                       case DESC92C_RATE9M:
+                               rate_idx = 5;
+                               break;
+                       case DESC92C_RATE12M:
+                               rate_idx = 6;
+                               break;
+                       case DESC92C_RATE18M:
+                               rate_idx = 7;
+                               break;
+                       case DESC92C_RATE24M:
+                               rate_idx = 8;
+                               break;
+                       case DESC92C_RATE36M:
+                               rate_idx = 9;
+                               break;
+                       case DESC92C_RATE48M:
+                               rate_idx = 10;
+                               break;
+                       case DESC92C_RATE54M:
+                               rate_idx = 11;
+                               break;
+                       default:
+                               rate_idx = 0;
+                               break;
+                       }
+               } else {
+                       switch (desc_rate) {
+                       case DESC92C_RATE6M:
+                               rate_idx = 0;
+                               break;
+                       case DESC92C_RATE9M:
+                               rate_idx = 1;
+                               break;
+                       case DESC92C_RATE12M:
+                               rate_idx = 2;
+                               break;
+                       case DESC92C_RATE18M:
+                               rate_idx = 3;
+                               break;
+                       case DESC92C_RATE24M:
+                               rate_idx = 4;
+                               break;
+                       case DESC92C_RATE36M:
+                               rate_idx = 5;
+                               break;
+                       case DESC92C_RATE48M:
+                               rate_idx = 6;
+                               break;
+                       case DESC92C_RATE54M:
+                               rate_idx = 7;
+                               break;
+                       default:
+                               rate_idx = 0;
+                               break;
+                       }
+               }
+       } else {
+               switch (desc_rate) {
+               case DESC92C_RATEMCS0:
+                       rate_idx = 0;
+                       break;
+               case DESC92C_RATEMCS1:
+                       rate_idx = 1;
+                       break;
+               case DESC92C_RATEMCS2:
+                       rate_idx = 2;
+                       break;
+               case DESC92C_RATEMCS3:
+                       rate_idx = 3;
+                       break;
+               case DESC92C_RATEMCS4:
+                       rate_idx = 4;
+                       break;
+               case DESC92C_RATEMCS5:
+                       rate_idx = 5;
+                       break;
+               case DESC92C_RATEMCS6:
+                       rate_idx = 6;
+                       break;
+               case DESC92C_RATEMCS7:
+                       rate_idx = 7;
+                       break;
+               case DESC92C_RATEMCS8:
+                       rate_idx = 8;
+                       break;
+               case DESC92C_RATEMCS9:
+                       rate_idx = 9;
+                       break;
+               case DESC92C_RATEMCS10:
+                       rate_idx = 10;
+                       break;
+               case DESC92C_RATEMCS11:
+                       rate_idx = 11;
+                       break;
+               case DESC92C_RATEMCS12:
+                       rate_idx = 12;
+                       break;
+               case DESC92C_RATEMCS13:
+                       rate_idx = 13;
+                       break;
+               case DESC92C_RATEMCS14:
+                       rate_idx = 14;
+                       break;
+               case DESC92C_RATEMCS15:
+                       rate_idx = 15;
+                       break;
+               default:
+                       rate_idx = 0;
+                       break;
+               }
+       }
+       return rate_idx;
+}
+
+static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw,
+                                        struct rtl_stats *pstatus, u8 *pdesc,
+                                        struct rx_fwinfo_8723be *p_drvinfo,
+                                        bool packet_match_bssid,
+                                        bool packet_toself,
+                                        bool packet_beacon)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
+       struct phy_sts_cck_8723e_t *cck_buf;
+       struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo;
+       struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+       char rx_pwr_all = 0, rx_pwr[4];
+       u8 rf_rx_num = 0, evm, pwdb_all;
+       u8 i, max_spatial_stream;
+       u32 rssi, total_rssi = 0;
+       bool is_cck = pstatus->is_cck;
+       u8 lan_idx, vga_idx;
+
+       /* Record it for next packet processing */
+       pstatus->packet_matchbssid = packet_match_bssid;
+       pstatus->packet_toself = packet_toself;
+       pstatus->packet_beacon = packet_beacon;
+       pstatus->rx_mimo_sig_qual[0] = -1;
+       pstatus->rx_mimo_sig_qual[1] = -1;
+
+       if (is_cck) {
+               u8 cck_highpwr;
+               u8 cck_agc_rpt;
+               /* CCK Driver info Structure is not the same as OFDM packet. */
+               cck_buf = (struct phy_sts_cck_8723e_t *)p_drvinfo;
+               cck_agc_rpt = cck_buf->cck_agc_rpt;
+
+               /* (1)Hardware does not provide RSSI for CCK
+                * (2)PWDB, Average PWDB cacluated by
+                * hardware (for rate adaptive)
+                */
+               if (ppsc->rfpwr_state == ERFON)
+                       cck_highpwr = (u8) rtl_get_bbreg(hw,
+                                                      RFPGA0_XA_HSSIPARAMETER2,
+                                                      BIT(9));
+               else
+                       cck_highpwr = false;
+
+               lan_idx = ((cck_agc_rpt & 0xE0) >> 5);
+               vga_idx = (cck_agc_rpt & 0x1f);
+               switch (lan_idx) {
+               case 7:
+                       if (vga_idx <= 27)/*VGA_idx = 27~2*/
+                               rx_pwr_all = -100 + 2 * (27 - vga_idx);
+                       else
+                               rx_pwr_all = -100;
+                       break;
+               case 6:/*VGA_idx = 2~0*/
+                       rx_pwr_all = -48 + 2 * (2 - vga_idx);
+                       break;
+               case 5:/*VGA_idx = 7~5*/
+                       rx_pwr_all = -42 + 2 * (7 - vga_idx);
+                       break;
+               case 4:/*VGA_idx = 7~4*/
+                       rx_pwr_all = -36 + 2 * (7 - vga_idx);
+                       break;
+               case 3:/*VGA_idx = 7~0*/
+                       rx_pwr_all = -24 + 2 * (7 - vga_idx);
+                       break;
+               case 2:
+                       if (cck_highpwr)/*VGA_idx = 5~0*/
+                               rx_pwr_all = -12 + 2 * (5 - vga_idx);
+                       else
+                               rx_pwr_all = -6 + 2 * (5 - vga_idx);
+                       break;
+               case 1:
+                       rx_pwr_all = 8 - 2 * vga_idx;
+                       break;
+               case 0:
+                       rx_pwr_all = 14 - 2 * vga_idx;
+                       break;
+               default:
+                       break;
+               }
+               rx_pwr_all += 6;
+               pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+               /* CCK gain is smaller than OFDM/MCS gain,  */
+               /* so we add gain diff by experiences,
+                * the val is 6
+                */
+               pwdb_all += 6;
+               if (pwdb_all > 100)
+                       pwdb_all = 100;
+               /* modify the offset to make the same gain index with OFDM. */
+               if (pwdb_all > 34 && pwdb_all <= 42)
+                       pwdb_all -= 2;
+               else if (pwdb_all > 26 && pwdb_all <= 34)
+                       pwdb_all -= 6;
+               else if (pwdb_all > 14 && pwdb_all <= 26)
+                       pwdb_all -= 8;
+               else if (pwdb_all > 4 && pwdb_all <= 14)
+                       pwdb_all -= 4;
+               if (!cck_highpwr) {
+                       if (pwdb_all >= 80)
+                               pwdb_all = ((pwdb_all - 80) << 1) +
+                                          ((pwdb_all - 80) >> 1) + 80;
+                       else if ((pwdb_all <= 78) && (pwdb_all >= 20))
+                               pwdb_all += 3;
+                       if (pwdb_all > 100)
+                               pwdb_all = 100;
+               }
+
+               pstatus->rx_pwdb_all = pwdb_all;
+               pstatus->recvsignalpower = rx_pwr_all;
+
+               /* (3) Get Signal Quality (EVM) */
+               if (packet_match_bssid) {
+                       u8 sq;
+
+                       if (pstatus->rx_pwdb_all > 40) {
+                               sq = 100;
+                       } else {
+                               sq = cck_buf->sq_rpt;
+                               if (sq > 64)
+                                       sq = 0;
+                               else if (sq < 20)
+                                       sq = 100;
+                               else
+                                       sq = ((64 - sq) * 100) / 44;
+                       }
+
+                       pstatus->signalquality = sq;
+                       pstatus->rx_mimo_sig_qual[0] = sq;
+                       pstatus->rx_mimo_sig_qual[1] = -1;
+               }
+       } else {
+               rtlpriv->dm.rfpath_rxenable[0] = true;
+               rtlpriv->dm.rfpath_rxenable[1] = true;
+
+               /* (1)Get RSSI for HT rate */
+               for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
+                       /* we will judge RF RX path now. */
+                       if (rtlpriv->dm.rfpath_rxenable[i])
+                               rf_rx_num++;
+
+                       rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f)*2) - 110;
+
+                       /* Translate DBM to percentage. */
+                       rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
+                       total_rssi += rssi;
+
+                       /* Get Rx snr value in DB */
+                       rtlpriv->stats.rx_snr_db[i] =
+                                       (long)(p_drvinfo->rxsnr[i] / 2);
+
+                       /* Record Signal Strength for next packet */
+                       if (packet_match_bssid)
+                               pstatus->rx_mimo_signalstrength[i] = (u8) rssi;
+               }
+
+               /* (2)PWDB, Avg cacluated by hardware (for rate adaptive) */
+               rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+
+               pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+               pstatus->rx_pwdb_all = pwdb_all;
+               pstatus->rxpower = rx_pwr_all;
+               pstatus->recvsignalpower = rx_pwr_all;
+
+               /* (3)EVM of HT rate */
+               if (pstatus->is_ht && pstatus->rate >= DESC92C_RATEMCS8 &&
+                   pstatus->rate <= DESC92C_RATEMCS15)
+                       max_spatial_stream = 2;
+               else
+                       max_spatial_stream = 1;
+
+               for (i = 0; i < max_spatial_stream; i++) {
+                       evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+
+                       if (packet_match_bssid) {
+                               /* Fill value in RFD, Get the first
+                                * spatial stream only
+                                */
+                               if (i == 0)
+                                       pstatus->signalquality =
+                                                       (u8) (evm & 0xff);
+                               pstatus->rx_mimo_sig_qual[i] =
+                                                       (u8) (evm & 0xff);
+                       }
+               }
+               if (packet_match_bssid) {
+                       for (i = RF90_PATH_A; i <= RF90_PATH_B; i++)
+                               rtl_priv(hw)->dm.cfo_tail[i] =
+                                       (char)p_phystrpt->path_cfotail[i];
+
+                       rtl_priv(hw)->dm.packet_count++;
+                       if (rtl_priv(hw)->dm.packet_count == 0xffffffff)
+                               rtl_priv(hw)->dm.packet_count = 0;
+               }
+       }
+
+       /* UI BSS List signal strength(in percentage),
+        * make it good looking, from 0~100.
+        */
+       if (is_cck)
+               pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+                                                               pwdb_all));
+       else if (rf_rx_num != 0)
+               pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+                                               total_rssi /= rf_rx_num));
+       /*HW antenna diversity*/
+       rtldm->fat_table.antsel_rx_keep_0 = p_phystrpt->ant_sel;
+       rtldm->fat_table.antsel_rx_keep_1 = p_phystrpt->ant_sel_b;
+       rtldm->fat_table.antsel_rx_keep_2 = p_phystrpt->antsel_rx_keep_2;
+}
+
+static void _rtl8723be_translate_rx_signal_stuff(struct ieee80211_hw *hw,
+                                       struct sk_buff *skb,
+                                       struct rtl_stats *pstatus,
+                                       u8 *pdesc,
+                                       struct rx_fwinfo_8723be *p_drvinfo)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct ieee80211_hdr *hdr;
+       u8 *tmp_buf;
+       u8 *praddr;
+       u8 *psaddr;
+       u16 fc, type;
+       bool packet_matchbssid, packet_toself, packet_beacon;
+
+       tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
+
+       hdr = (struct ieee80211_hdr *)tmp_buf;
+       fc = le16_to_cpu(hdr->frame_control);
+       type = WLAN_FC_GET_TYPE(hdr->frame_control);
+       praddr = hdr->addr1;
+       psaddr = ieee80211_get_SA(hdr);
+       memcpy(pstatus->psaddr, psaddr, ETH_ALEN);
+
+       packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
+            (!ether_addr_equal(mac->bssid, (fc & IEEE80211_FCTL_TODS) ?
+                               hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ?
+                               hdr->addr2 : hdr->addr3)) &&
+                               (!pstatus->hwerror) &&
+                               (!pstatus->crc) && (!pstatus->icv));
+
+       packet_toself = packet_matchbssid &&
+           (!ether_addr_equal(praddr, rtlefuse->dev_addr));
+
+       /* YP: packet_beacon is not initialized,
+        * this assignment is neccesary,
+        * otherwise it counld be true in this case
+        * the situation is much worse in Kernel 3.10
+        */
+       if (ieee80211_is_beacon(hdr->frame_control))
+               packet_beacon = true;
+       else
+               packet_beacon = false;
+
+       if (packet_beacon && packet_matchbssid)
+               rtl_priv(hw)->dm.dbginfo.num_qry_beacon_pkt++;
+
+       _rtl8723be_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
+                                    packet_matchbssid,
+                                    packet_toself,
+                                    packet_beacon);
+
+       rtl_process_phyinfo(hw, tmp_buf, pstatus);
+}
+
+static void _rtl8723be_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
+                                       u8 *virtualaddress)
+{
+       u32 dwtmp = 0;
+       memset(virtualaddress, 0, 8);
+
+       SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num);
+       if (ptcb_desc->empkt_num == 1) {
+               dwtmp = ptcb_desc->empkt_len[0];
+       } else {
+               dwtmp = ptcb_desc->empkt_len[0];
+               dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+               dwtmp += ptcb_desc->empkt_len[1];
+       }
+       SET_EARLYMODE_LEN0(virtualaddress, dwtmp);
+
+       if (ptcb_desc->empkt_num <= 3) {
+               dwtmp = ptcb_desc->empkt_len[2];
+       } else {
+               dwtmp = ptcb_desc->empkt_len[2];
+               dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+               dwtmp += ptcb_desc->empkt_len[3];
+       }
+       SET_EARLYMODE_LEN1(virtualaddress, dwtmp);
+       if (ptcb_desc->empkt_num <= 5) {
+               dwtmp = ptcb_desc->empkt_len[4];
+       } else {
+               dwtmp = ptcb_desc->empkt_len[4];
+               dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+               dwtmp += ptcb_desc->empkt_len[5];
+       }
+       SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF);
+       SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4);
+       if (ptcb_desc->empkt_num <= 7) {
+               dwtmp = ptcb_desc->empkt_len[6];
+       } else {
+               dwtmp = ptcb_desc->empkt_len[6];
+               dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+               dwtmp += ptcb_desc->empkt_len[7];
+       }
+       SET_EARLYMODE_LEN3(virtualaddress, dwtmp);
+       if (ptcb_desc->empkt_num <= 9) {
+               dwtmp = ptcb_desc->empkt_len[8];
+       } else {
+               dwtmp = ptcb_desc->empkt_len[8];
+               dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+               dwtmp += ptcb_desc->empkt_len[9];
+       }
+       SET_EARLYMODE_LEN4(virtualaddress, dwtmp);
+}
+
+bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw,
+                            struct rtl_stats *status,
+                            struct ieee80211_rx_status *rx_status,
+                            u8 *pdesc, struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rx_fwinfo_8723be *p_drvinfo;
+       struct ieee80211_hdr *hdr;
+
+       u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+       status->packet_report_type = (u8)GET_RX_STATUS_DESC_RPT_SEL(pdesc);
+       if (status->packet_report_type == TX_REPORT2)
+               status->length = (u16) GET_RX_RPT2_DESC_PKT_LEN(pdesc);
+       else
+               status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
+       status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+                                 RX_DRV_INFO_SIZE_UNIT;
+       status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03);
+       status->icv = (u16) GET_RX_DESC_ICV(pdesc);
+       status->crc = (u16) GET_RX_DESC_CRC32(pdesc);
+       status->hwerror = (status->crc | status->icv);
+       status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
+       status->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
+       status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
+       status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
+       status->isfirst_ampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
+       if (status->packet_report_type == NORMAL_RX)
+               status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
+       status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+       status->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
+
+       status->is_cck = RTL8723E_RX_HAL_IS_CCK_RATE(status->rate);
+
+       status->macid = GET_RX_DESC_MACID(pdesc);
+       if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+               status->wake_match = BIT(2);
+       else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+               status->wake_match = BIT(1);
+       else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc))
+               status->wake_match = BIT(0);
+       else
+               status->wake_match = 0;
+       if (status->wake_match)
+               RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD,
+                        "GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n",
+                        status->wake_match);
+       rx_status->freq = hw->conf.chandef.chan->center_freq;
+       rx_status->band = hw->conf.chandef.chan->band;
+
+
+       hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size +
+                                      status->rx_bufshift);
+
+       if (status->crc)
+               rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+       if (status->rx_is40Mhzpacket)
+               rx_status->flag |= RX_FLAG_40MHZ;
+
+       if (status->is_ht)
+               rx_status->flag |= RX_FLAG_HT;
+
+       rx_status->flag |= RX_FLAG_MACTIME_START;
+
+       /* hw will set status->decrypted true, if it finds the
+        * frame is open data frame or mgmt frame.
+        * So hw will not decryption robust managment frame
+        * for IEEE80211w but still set status->decrypted
+        * true, so here we should set it back to undecrypted
+        * for IEEE80211w frame, and mac80211 sw will help
+        * to decrypt it
+        */
+       if (status->decrypted) {
+               if (!hdr) {
+                       WARN_ON_ONCE(true);
+                       pr_err("decrypted is true but hdr NULL in skb %p\n",
+                              rtl_get_hdr(skb));
+                       return false;
+               }
+
+               if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+                   (ieee80211_has_protected(hdr->frame_control)))
+                       rx_status->flag &= ~RX_FLAG_DECRYPTED;
+               else
+                       rx_status->flag |= RX_FLAG_DECRYPTED;
+       }
+
+       /* rate_idx: index of data rate into band's
+        * supported rates or MCS index if HT rates
+        * are use (RX_FLAG_HT)
+        * Notice: this is diff with windows define
+        */
+       rx_status->rate_idx = _rtl8723be_rate_mapping(hw, status->is_ht,
+                                                     status->rate);
+
+       rx_status->mactime = status->timestamp_low;
+       if (phystatus) {
+               p_drvinfo = (struct rx_fwinfo_8723be *)(skb->data +
+                                                       status->rx_bufshift);
+
+               _rtl8723be_translate_rx_signal_stuff(hw, skb, status,
+                                                    pdesc, p_drvinfo);
+       }
+
+       /*rx_status->qual = status->signal; */
+       rx_status->signal = status->recvsignalpower + 10;
+       if (status->packet_report_type == TX_REPORT2) {
+               status->macid_valid_entry[0] =
+                        GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
+               status->macid_valid_entry[1] =
+                        GET_RX_RPT2_DESC_MACID_VALID_2(pdesc);
+       }
+       return true;
+}
+
+void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw,
+                           struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+                           u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+                           struct ieee80211_sta *sta, struct sk_buff *skb,
+                           u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 *pdesc = (u8 *)pdesc_tx;
+       u16 seq_number;
+       __le16 fc = hdr->frame_control;
+       unsigned int buf_len = 0;
+       unsigned int skb_len = skb->len;
+       u8 fw_qsel = _rtl8723be_map_hwqueue_to_fwqueue(skb, hw_queue);
+       bool firstseg = ((hdr->seq_ctrl &
+                         cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+       bool lastseg = ((hdr->frame_control &
+                        cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+       dma_addr_t mapping;
+       u8 bw_40 = 0;
+       u8 short_gi = 0;
+
+       if (mac->opmode == NL80211_IFTYPE_STATION) {
+               bw_40 = mac->bw_40;
+       } else if (mac->opmode == NL80211_IFTYPE_AP ||
+               mac->opmode == NL80211_IFTYPE_ADHOC) {
+               if (sta)
+                       bw_40 = sta->ht_cap.cap &
+                               IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+       }
+       seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+       rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
+       /* reserve 8 byte for AMPDU early mode */
+       if (rtlhal->earlymode_enable) {
+               skb_push(skb, EM_HDR_LEN);
+               memset(skb->data, 0, EM_HDR_LEN);
+       }
+       buf_len = skb->len;
+       mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+                                PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "DMA mapping error");
+               return;
+       }
+       CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8723be));
+       if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+               firstseg = true;
+               lastseg = true;
+       }
+       if (firstseg) {
+               if (rtlhal->earlymode_enable) {
+                       SET_TX_DESC_PKT_OFFSET(pdesc, 1);
+                       SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN +
+                                          EM_HDR_LEN);
+                       if (ptcb_desc->empkt_num) {
+                               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                                        "Insert 8 byte.pTcb->EMPktNum:%d\n",
+                                         ptcb_desc->empkt_num);
+                               _rtl8723be_insert_emcontent(ptcb_desc,
+                                                           (u8 *)(skb->data));
+                       }
+               } else {
+                       SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+               }
+
+               /* ptcb_desc->use_driver_rate = true; */
+               SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
+               if (ptcb_desc->hw_rate > DESC92C_RATEMCS0)
+                       short_gi = (ptcb_desc->use_shortgi) ? 1 : 0;
+               else
+                       short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0;
+
+               SET_TX_DESC_DATA_SHORTGI(pdesc, short_gi);
+
+               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       SET_TX_DESC_AGG_ENABLE(pdesc, 1);
+                       SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14);
+               }
+               SET_TX_DESC_SEQ(pdesc, seq_number);
+               SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable &&
+                                               !ptcb_desc->cts_enable) ?
+                                               1 : 0));
+               SET_TX_DESC_HW_RTS_ENABLE(pdesc, 0);
+               SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ?
+                                             1 : 0));
+
+               SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
+
+               SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
+               SET_TX_DESC_RTS_SHORT(pdesc,
+                       ((ptcb_desc->rts_rate <= DESC92C_RATE54M) ?
+                        (ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
+                        (ptcb_desc->rts_use_shortgi ? 1 : 0)));
+
+               if (ptcb_desc->btx_enable_sw_calc_duration)
+                       SET_TX_DESC_NAV_USE_HDR(pdesc, 1);
+
+               if (bw_40) {
+                       if (ptcb_desc->packet_bw) {
+                               SET_TX_DESC_DATA_BW(pdesc, 1);
+                               SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
+                       } else {
+                               SET_TX_DESC_DATA_BW(pdesc, 0);
+                               SET_TX_DESC_TX_SUB_CARRIER(pdesc, mac->cur_40_prime_sc);
+                       }
+               } else {
+                       SET_TX_DESC_DATA_BW(pdesc, 0);
+                       SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+               }
+
+               SET_TX_DESC_LINIP(pdesc, 0);
+               SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb_len);
+               if (sta) {
+                       u8 ampdu_density = sta->ht_cap.ampdu_density;
+                       SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
+               }
+               if (info->control.hw_key) {
+                       struct ieee80211_key_conf *keyconf =
+                                               info->control.hw_key;
+                       switch (keyconf->cipher) {
+                       case WLAN_CIPHER_SUITE_WEP40:
+                       case WLAN_CIPHER_SUITE_WEP104:
+                       case WLAN_CIPHER_SUITE_TKIP:
+                               SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+                               break;
+                       case WLAN_CIPHER_SUITE_CCMP:
+                               SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+                               break;
+                       default:
+                               SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+                               break;
+                       }
+               }
+
+               SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+               SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+               SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
+               SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ?
+                                      1 : 0);
+               SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
+
+               if (ieee80211_is_data_qos(fc)) {
+                       if (mac->rdg_en) {
+                               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                                        "Enable RDG function.\n");
+                               SET_TX_DESC_RDG_ENABLE(pdesc, 1);
+                               SET_TX_DESC_HTC(pdesc, 1);
+                       }
+               }
+       }
+
+       SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
+       SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
+       SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len);
+       SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+       SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
+       SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+
+       if (!ieee80211_is_data_qos(fc))  {
+               SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+               SET_TX_DESC_HWSEQ_SEL(pdesc, 0);
+       }
+       SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
+       if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+           is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
+               SET_TX_DESC_BMC(pdesc, 1);
+       }
+       RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
+}
+
+void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+                              bool b_firstseg, bool b_lastseg,
+                              struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       u8 fw_queue = QSLT_BEACON;
+
+       dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+                                           skb->data, skb->len,
+                                           PCI_DMA_TODEVICE);
+
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
+       CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
+
+       SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+
+       SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+
+       SET_TX_DESC_SEQ(pdesc, 0);
+
+       SET_TX_DESC_LINIP(pdesc, 0);
+
+       SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
+
+       SET_TX_DESC_FIRST_SEG(pdesc, 1);
+       SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+       SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+
+       SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+
+       SET_TX_DESC_RATE_ID(pdesc, 0);
+       SET_TX_DESC_MACID(pdesc, 0);
+
+       SET_TX_DESC_OWN(pdesc, 1);
+
+       SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
+
+       SET_TX_DESC_FIRST_SEG(pdesc, 1);
+       SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+       SET_TX_DESC_USE_RATE(pdesc, 1);
+}
+
+void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                       u8 desc_name, u8 *val)
+{
+       if (istx) {
+               switch (desc_name) {
+               case HW_DESC_OWN:
+                       SET_TX_DESC_OWN(pdesc, 1);
+                       break;
+               case HW_DESC_TX_NEXTDESC_ADDR:
+                       SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val);
+                       break;
+               default:
+                       RT_ASSERT(false, "ERR txdesc :%d not process\n",
+                                 desc_name);
+                       break;
+               }
+       } else {
+               switch (desc_name) {
+               case HW_DESC_RXOWN:
+                       SET_RX_DESC_OWN(pdesc, 1);
+                       break;
+               case HW_DESC_RXBUFF_ADDR:
+                       SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *)val);
+                       break;
+               case HW_DESC_RXPKT_LEN:
+                       SET_RX_DESC_PKT_LEN(pdesc, *(u32 *)val);
+                       break;
+               case HW_DESC_RXERO:
+                       SET_RX_DESC_EOR(pdesc, 1);
+                       break;
+               default:
+                       RT_ASSERT(false, "ERR rxdesc :%d not process\n",
+                                 desc_name);
+                       break;
+               }
+       }
+}
+
+u32 rtl8723be_get_desc(u8 *pdesc, bool istx, u8 desc_name)
+{
+       u32 ret = 0;
+
+       if (istx) {
+               switch (desc_name) {
+               case HW_DESC_OWN:
+                       ret = GET_TX_DESC_OWN(pdesc);
+                       break;
+               case HW_DESC_TXBUFF_ADDR:
+                       ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc);
+                       break;
+               default:
+                       RT_ASSERT(false, "ERR txdesc :%d not process\n",
+                                 desc_name);
+                       break;
+               }
+       } else {
+               switch (desc_name) {
+               case HW_DESC_OWN:
+                       ret = GET_RX_DESC_OWN(pdesc);
+                       break;
+               case HW_DESC_RXPKT_LEN:
+                       ret = GET_RX_DESC_PKT_LEN(pdesc);
+                       break;
+               default:
+                       RT_ASSERT(false, "ERR rxdesc :%d not process\n",
+                                 desc_name);
+                       break;
+               }
+       }
+       return ret;
+}
+
+bool rtl8723be_is_tx_desc_closed(struct ieee80211_hw *hw,
+                                u8 hw_queue, u16 index)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+       u8 *entry = (u8 *)(&ring->desc[ring->idx]);
+       u8 own = (u8) rtl8723be_get_desc(entry, true, HW_DESC_OWN);
+
+       /*beacon packet will only use the first
+        *descriptor by default, and the own may not
+        *be cleared by the hardware
+        */
+       if (own)
+               return false;
+       else
+               return true;
+}
+
+void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       if (hw_queue == BEACON_QUEUE) {
+               rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4));
+       } else {
+               rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG,
+                              BIT(0) << (hw_queue));
+       }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h
new file mode 100644 (file)
index 0000000..102f33d
--- /dev/null
@@ -0,0 +1,617 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723BE_TRX_H__
+#define __RTL8723BE_TRX_H__
+
+#define TX_DESC_SIZE                           40
+#define TX_DESC_AGGR_SUBFRAME_SIZE             32
+
+#define RX_DESC_SIZE                           32
+#define RX_DRV_INFO_SIZE_UNIT                  8
+
+#define        TX_DESC_NEXT_DESC_OFFSET                40
+#define USB_HWDESC_HEADER_LEN                  40
+#define CRCLENGTH                              4
+
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_BMC(__pdesc, __val)                        \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val)                        \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val)              \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GF(__pdesc, __val)                 \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val)                        \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_PKT_SIZE(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc, 0, 16)
+#define GET_TX_DESC_OFFSET(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc, 16, 8)
+#define GET_TX_DESC_BMC(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 24, 1)
+#define GET_TX_DESC_HTC(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 25, 1)
+#define GET_TX_DESC_LAST_SEG(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_TX_DESC_FIRST_SEG(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_TX_DESC_LINIP(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_TX_DESC_NO_ACM(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_TX_DESC_GF(__pdesc)                                \
+       LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_TX_DESC_OWN(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_TX_DESC_MACID(__pdesc, __val)              \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 7, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
+#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
+#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val)       \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val)               \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
+#define SET_TX_DESC_RATE_ID(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 5, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 5, __val)
+
+
+#define SET_TX_DESC_PAID(__pdesc, __val)               \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 9, __val)
+#define SET_TX_DESC_CCA_RTS(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 10, 2, __val)
+#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val)
+#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val)
+#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val)
+#define SET_TX_DESC_AGG_BREAK(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
+#define SET_TX_DESC_RAW(__pdesc, __val)                        \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
+#define SET_TX_DESC_SPE_RPT(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val)
+#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
+#define SET_TX_DESC_BT_INT(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val)
+#define SET_TX_DESC_GID(__pdesc, __val)                        \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 6, __val)
+
+
+#define SET_TX_DESC_WHEADER_LEN(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 4, __val)
+#define SET_TX_DESC_CHK_EN(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 4, 1, __val)
+#define SET_TX_DESC_EARLY_MODE(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 5, 1, __val)
+#define SET_TX_DESC_HWSEQ_SEL(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 6, 2, __val)
+#define SET_TX_DESC_USE_RATE(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 1, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val)     \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 9, 1, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 10, 1, __val)
+#define SET_TX_DESC_CTS2SELF(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 12, 1, __val)
+#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 13, 1, __val)
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 15, 1, __val)
+#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 1, __val)
+#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 17, 5, __val)
+#define SET_TX_DESC_NDPA(__pdesc, __val)               \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 22, 2, __val)
+#define SET_TX_DESC_AMPDU_MAX_TIME(__pdesc, __val)     \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 24, 8, __val)
+
+
+#define SET_TX_DESC_TX_RATE(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 7, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 5, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val)  \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 4, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 17, 1, __val)
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val)   \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 6, __val)
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 5, __val)
+
+
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val)     \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 4, __val)
+#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val)       \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 4, 1, __val)
+#define SET_TX_DESC_DATA_BW(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 5, 2, __val)
+#define SET_TX_DESC_DATA_LDPC(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val)
+#define SET_TX_DESC_DATA_STBC(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 2, __val)
+#define SET_TX_DESC_CTROL_STBC(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 10, 2, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 12, 1, __val)
+#define SET_TX_DESC_RTS_SC(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val)
+
+
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val)     \
+       SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val)
+
+#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc)            \
+       LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
+
+#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+32, 15, 1, __val)
+
+#define SET_TX_DESC_SEQ(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+36, 12, 12, __val)
+
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val)  \
+       SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
+
+#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc)         \
+       LE_BITS_TO_4BYTE(__pdesc+40, 0, 32)
+
+
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val)  \
+       SET_BITS_TO_LE_4BYTE(__pdesc+48, 0, 32, __val)
+
+#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc)         \
+       LE_BITS_TO_4BYTE(__pdesc+48, 0, 32)
+
+#define GET_RX_DESC_PKT_LEN(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc, 0, 14)
+#define GET_RX_DESC_CRC32(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 14, 1)
+#define GET_RX_DESC_ICV(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 15, 1)
+#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc, 16, 4)
+#define GET_RX_DESC_SECURITY(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc, 20, 3)
+#define GET_RX_DESC_QOS(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 23, 1)
+#define GET_RX_DESC_SHIFT(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 24, 2)
+#define GET_RX_DESC_PHYST(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_RX_DESC_SWDEC(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_RX_DESC_LS(__pdesc)                        \
+       LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_RX_DESC_FS(__pdesc)                        \
+       LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_RX_DESC_EOR(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_RX_DESC_OWN(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_RX_DESC_PKT_LEN(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
+#define SET_RX_DESC_EOR(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_RX_DESC_OWN(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_RX_DESC_MACID(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+4, 0, 7)
+#define GET_RX_DESC_TID(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+4, 8, 4)
+#define GET_RX_DESC_AMSDU(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
+#define GET_RX_STATUS_DESC_RXID_MATCH(__pdesc)         \
+       LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_RX_DESC_PAGGR(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_RX_DESC_A1_FIT(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_RX_DESC_CHKERR(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
+#define GET_RX_DESC_IPVER(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
+#define GET_RX_STATUS_DESC_IS_TCPUDP(__pdesc)          \
+       LE_BITS_TO_4BYTE(__pdesc+4, 22, 1)
+#define GET_RX_STATUS_DESC_CHK_VLD(__pdesc)            \
+       LE_BITS_TO_4BYTE(__pdesc+4, 23, 1)
+#define GET_RX_DESC_PAM(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
+#define GET_RX_DESC_PWR(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
+#define GET_RX_DESC_MD(__pdesc)                        \
+       LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
+#define GET_RX_DESC_MF(__pdesc)                        \
+       LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
+#define GET_RX_DESC_TYPE(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
+#define GET_RX_DESC_MC(__pdesc)                        \
+       LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
+#define GET_RX_DESC_BC(__pdesc)                        \
+       LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
+
+
+#define GET_RX_DESC_SEQ(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
+#define GET_RX_DESC_FRAG(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
+#define GET_RX_STATUS_DESC_RX_IS_QOS(__pdesc)          \
+       LE_BITS_TO_4BYTE(__pdesc+8, 16, 1)
+#define GET_RX_STATUS_DESC_WLANHD_IV_LEN(__pdesc)      \
+       LE_BITS_TO_4BYTE(__pdesc+8, 18, 6)
+#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc)            \
+       LE_BITS_TO_4BYTE(__pdesc+8, 28, 1)
+
+
+#define GET_RX_DESC_RXMCS(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+12, 0, 7)
+#define GET_RX_DESC_RXHT(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+12, 6, 1)
+#define GET_RX_STATUS_DESC_RX_GF(__pdesc)              \
+       LE_BITS_TO_4BYTE(__pdesc+12, 7, 1)
+#define GET_RX_DESC_HTC(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
+#define GET_RX_STATUS_DESC_EOSP(__pdesc)               \
+       LE_BITS_TO_4BYTE(__pdesc+12, 11, 1)
+#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc)          \
+       LE_BITS_TO_4BYTE(__pdesc+12, 12, 2)
+
+#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc)      \
+       LE_BITS_TO_4BYTE(__pdesc+12, 29, 1)
+#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc)      \
+       LE_BITS_TO_4BYTE(__pdesc+12, 30, 1)
+#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+12, 31, 1)
+
+#define GET_RX_DESC_SPLCP(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+16, 0, 1)
+#define GET_RX_STATUS_DESC_LDPC(__pdesc)               \
+       LE_BITS_TO_4BYTE(__pdesc+16, 1, 1)
+#define GET_RX_STATUS_DESC_STBC(__pdesc)               \
+       LE_BITS_TO_4BYTE(__pdesc+16, 2, 1)
+#define GET_RX_DESC_BW(__pdesc)                        \
+       LE_BITS_TO_4BYTE(__pdesc+16, 4, 2)
+
+#define GET_RX_DESC_TSFL(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
+
+#define GET_RX_DESC_BUFF_ADDR(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+24, 0, 32)
+#define GET_RX_DESC_BUFF_ADDR64(__pdesc)               \
+       LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
+
+#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
+#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val)        \
+       SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+
+
+/* TX report 2 format in Rx desc*/
+
+#define GET_RX_RPT2_DESC_PKT_LEN(__rxstatusdesc)       \
+       LE_BITS_TO_4BYTE(__rxstatusdesc, 0, 9)
+#define GET_RX_RPT2_DESC_MACID_VALID_1(__rxstatusdesc) \
+       LE_BITS_TO_4BYTE(__rxstatusdesc+16, 0, 32)
+#define GET_RX_RPT2_DESC_MACID_VALID_2(__rxstatusdesc) \
+       LE_BITS_TO_4BYTE(__rxstatusdesc+20, 0, 32)
+
+#define SET_EARLYMODE_PKTNUM(__paddr, __value)         \
+       SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __value)
+#define SET_EARLYMODE_LEN0(__paddr, __value)           \
+       SET_BITS_TO_LE_4BYTE(__paddr, 4, 12, __value)
+#define SET_EARLYMODE_LEN1(__paddr, __value)           \
+       SET_BITS_TO_LE_4BYTE(__paddr, 16, 12, __value)
+#define SET_EARLYMODE_LEN2_1(__paddr, __value)         \
+       SET_BITS_TO_LE_4BYTE(__paddr, 28, 4, __value)
+#define SET_EARLYMODE_LEN2_2(__paddr, __value)         \
+       SET_BITS_TO_LE_4BYTE(__paddr+4, 0, 8, __value)
+#define SET_EARLYMODE_LEN3(__paddr, __value)           \
+       SET_BITS_TO_LE_4BYTE(__paddr+4, 8, 12, __value)
+#define SET_EARLYMODE_LEN4(__paddr, __value)           \
+       SET_BITS_TO_LE_4BYTE(__paddr+4, 20, 12, __value)
+
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)              \
+do {                                                           \
+       if (_size > TX_DESC_NEXT_DESC_OFFSET)                   \
+               memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);   \
+       else                                                    \
+               memset(__pdesc, 0, _size);                      \
+} while (0)
+
+struct phy_rx_agc_info_t {
+       #ifdef __LITTLE_ENDIAN
+               u8 gain:7, trsw:1;
+       #else
+               u8 trsw:1, gain:7;
+       #endif
+};
+struct phy_status_rpt {
+       struct phy_rx_agc_info_t path_agc[2];
+       u8 ch_corr[2];
+       u8 cck_sig_qual_ofdm_pwdb_all;
+       u8 cck_agc_rpt_ofdm_cfosho_a;
+       u8 cck_rpt_b_ofdm_cfosho_b;
+       u8 rsvd_1;/* ch_corr_msb; */
+       u8 noise_power_db_msb;
+       char path_cfotail[2];
+       u8 pcts_mask[2];
+       char stream_rxevm[2];
+       u8 path_rxsnr[2];
+       u8 noise_power_db_lsb;
+       u8 rsvd_2[3];
+       u8 stream_csi[2];
+       u8 stream_target_csi[2];
+       u8 sig_evm;
+       u8 rsvd_3;
+#ifdef __LITTLE_ENDIAN
+       u8 antsel_rx_keep_2:1;  /*ex_intf_flg:1;*/
+       u8 sgi_en:1;
+       u8 rxsc:2;
+       u8 idle_long:1;
+       u8 r_ant_train_en:1;
+       u8 ant_sel_b:1;
+       u8 ant_sel:1;
+#else  /* _BIG_ENDIAN_ */
+       u8 ant_sel:1;
+       u8 ant_sel_b:1;
+       u8 r_ant_train_en:1;
+       u8 idle_long:1;
+       u8 rxsc:2;
+       u8 sgi_en:1;
+       u8 antsel_rx_keep_2:1;  /*ex_intf_flg:1;*/
+#endif
+} __packed;
+
+struct rx_fwinfo_8723be {
+       u8 gain_trsw[4];
+       u8 pwdb_all;
+       u8 cfosho[4];
+       u8 cfotail[4];
+       char rxevm[2];
+       char rxsnr[4];
+       u8 pdsnr[2];
+       u8 csi_current[2];
+       u8 csi_target[2];
+       u8 sigevm;
+       u8 max_ex_pwr;
+       u8 ex_intf_flag:1;
+       u8 sgi_en:1;
+       u8 rxsc:2;
+       u8 reserve:4;
+} __packed;
+
+struct tx_desc_8723be {
+       u32 pktsize:16;
+       u32 offset:8;
+       u32 bmc:1;
+       u32 htc:1;
+       u32 lastseg:1;
+       u32 firstseg:1;
+       u32 linip:1;
+       u32 noacm:1;
+       u32 gf:1;
+       u32 own:1;
+
+       u32 macid:6;
+       u32 rsvd0:2;
+       u32 queuesel:5;
+       u32 rd_nav_ext:1;
+       u32 lsig_txop_en:1;
+       u32 pifs:1;
+       u32 rateid:4;
+       u32 nav_usehdr:1;
+       u32 en_descid:1;
+       u32 sectype:2;
+       u32 pktoffset:8;
+
+       u32 rts_rc:6;
+       u32 data_rc:6;
+       u32 agg_en:1;
+       u32 rdg_en:1;
+       u32 bar_retryht:2;
+       u32 agg_break:1;
+       u32 morefrag:1;
+       u32 raw:1;
+       u32 ccx:1;
+       u32 ampdudensity:3;
+       u32 bt_int:1;
+       u32 ant_sela:1;
+       u32 ant_selb:1;
+       u32 txant_cck:2;
+       u32 txant_l:2;
+       u32 txant_ht:2;
+
+       u32 nextheadpage:8;
+       u32 tailpage:8;
+       u32 seq:12;
+       u32 cpu_handle:1;
+       u32 tag1:1;
+       u32 trigger_int:1;
+       u32 hwseq_en:1;
+
+       u32 rtsrate:5;
+       u32 apdcfe:1;
+       u32 qos:1;
+       u32 hwseq_ssn:1;
+       u32 userrate:1;
+       u32 dis_rtsfb:1;
+       u32 dis_datafb:1;
+       u32 cts2self:1;
+       u32 rts_en:1;
+       u32 hwrts_en:1;
+       u32 portid:1;
+       u32 pwr_status:3;
+       u32 waitdcts:1;
+       u32 cts2ap_en:1;
+       u32 txsc:2;
+       u32 stbc:2;
+       u32 txshort:1;
+       u32 txbw:1;
+       u32 rtsshort:1;
+       u32 rtsbw:1;
+       u32 rtssc:2;
+       u32 rtsstbc:2;
+
+       u32 txrate:6;
+       u32 shortgi:1;
+       u32 ccxt:1;
+       u32 txrate_fb_lmt:5;
+       u32 rtsrate_fb_lmt:4;
+       u32 retrylmt_en:1;
+       u32 txretrylmt:6;
+       u32 usb_txaggnum:8;
+
+       u32 txagca:5;
+       u32 txagcb:5;
+       u32 usemaxlen:1;
+       u32 maxaggnum:5;
+       u32 mcsg1maxlen:4;
+       u32 mcsg2maxlen:4;
+       u32 mcsg3maxlen:4;
+       u32 mcs7sgimaxlen:4;
+
+       u32 txbuffersize:16;
+       u32 sw_offset30:8;
+       u32 sw_offset31:4;
+       u32 rsvd1:1;
+       u32 antsel_c:1;
+       u32 null_0:1;
+       u32 null_1:1;
+
+       u32 txbuffaddr;
+       u32 txbufferaddr64;
+       u32 nextdescaddress;
+       u32 nextdescaddress64;
+
+       u32 reserve_pass_pcie_mm_limit[4];
+} __packed;
+
+struct rx_desc_8723be {
+       u32 length:14;
+       u32 crc32:1;
+       u32 icverror:1;
+       u32 drv_infosize:4;
+       u32 security:3;
+       u32 qos:1;
+       u32 shift:2;
+       u32 phystatus:1;
+       u32 swdec:1;
+       u32 lastseg:1;
+       u32 firstseg:1;
+       u32 eor:1;
+       u32 own:1;
+
+       u32 macid:6;
+       u32 tid:4;
+       u32 hwrsvd:5;
+       u32 paggr:1;
+       u32 faggr:1;
+       u32 a1_fit:4;
+       u32 a2_fit:4;
+       u32 pam:1;
+       u32 pwr:1;
+       u32 moredata:1;
+       u32 morefrag:1;
+       u32 type:2;
+       u32 mc:1;
+       u32 bc:1;
+
+       u32 seq:12;
+       u32 frag:4;
+       u32 nextpktlen:14;
+       u32 nextind:1;
+       u32 rsvd:1;
+
+       u32 rxmcs:6;
+       u32 rxht:1;
+       u32 amsdu:1;
+       u32 splcp:1;
+       u32 bandwidth:1;
+       u32 htc:1;
+       u32 tcpchk_rpt:1;
+       u32 ipcchk_rpt:1;
+       u32 tcpchk_valid:1;
+       u32 hwpcerr:1;
+       u32 hwpcind:1;
+       u32 iv0:16;
+
+       u32 iv1;
+
+       u32 tsfl;
+
+       u32 bufferaddress;
+       u32 bufferaddress64;
+
+} __packed;
+
+void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw,
+                           struct ieee80211_hdr *hdr, u8 *pdesc,
+                           u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+                           struct ieee80211_sta *sta, struct sk_buff *skb,
+                           u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
+bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw,
+                            struct rtl_stats *status,
+                            struct ieee80211_rx_status *rx_status,
+                            u8 *pdesc, struct sk_buff *skb);
+void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                       u8 desc_name, u8 *val);
+u32 rtl8723be_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+bool rtl8723be_is_tx_desc_closed(struct ieee80211_hw *hw,
+                                u8 hw_queue, u16 index);
+void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+                              bool b_firstseg, bool b_lastseg,
+                              struct sk_buff *skb);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/Makefile b/drivers/net/wireless/rtlwifi/rtl8723com/Makefile
new file mode 100644 (file)
index 0000000..345a68a
--- /dev/null
@@ -0,0 +1,9 @@
+rtl8723-common-objs :=         \
+               main.o          \
+               dm_common.o     \
+               fw_common.o     \
+               phy_common.o
+
+obj-$(CONFIG_RTL8723_COMMON) += rtl8723-common.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c
new file mode 100644 (file)
index 0000000..4e254b7
--- /dev/null
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "dm_common.h"
+#include "../rtl8723ae/dm.h"
+#include <linux/module.h>
+
+/* These routines are common to RTL8723AE and RTL8723bE */
+
+void rtl8723_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm.dynamic_txpower_enable = false;
+
+       rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+       rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+}
+EXPORT_SYMBOL_GPL(rtl8723_dm_init_dynamic_txpower);
+
+void rtl8723_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm.current_turbo_edca = false;
+       rtlpriv->dm.is_any_nonbepkts = false;
+       rtlpriv->dm.is_cur_rdlstate = false;
+}
+EXPORT_SYMBOL_GPL(rtl8723_dm_init_edca_turbo);
+
+void rtl8723_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm_pstable.pre_ccastate = CCA_MAX;
+       rtlpriv->dm_pstable.cur_ccasate = CCA_MAX;
+       rtlpriv->dm_pstable.pre_rfstate = RF_MAX;
+       rtlpriv->dm_pstable.cur_rfstate = RF_MAX;
+       rtlpriv->dm_pstable.rssi_val_min = 0;
+       rtlpriv->dm_pstable.initialize = 0;
+}
+EXPORT_SYMBOL_GPL(rtl8723_dm_init_dynamic_bb_powersaving);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h
new file mode 100644 (file)
index 0000000..5c1b94c
--- /dev/null
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __DM_COMMON_H__
+#define __DM_COMMON_H__
+
+void rtl8723_dm_init_dynamic_txpower(struct ieee80211_hw *hw);
+void rtl8723_dm_init_edca_turbo(struct ieee80211_hw *hw);
+void rtl8723_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c
new file mode 100644 (file)
index 0000000..c12da55
--- /dev/null
@@ -0,0 +1,329 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "fw_common.h"
+#include <linux/module.h>
+
+void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmp;
+
+       if (enable) {
+               tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+               rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
+
+               tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+               rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
+
+               tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
+               rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
+       } else {
+               tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+               rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
+
+               rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
+       }
+}
+EXPORT_SYMBOL_GPL(rtl8723_enable_fw_download);
+
+void rtl8723_fw_block_write(struct ieee80211_hw *hw,
+                           const u8 *buffer, u32 size)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 blocksize = sizeof(u32);
+       u8 *bufferptr = (u8 *)buffer;
+       u32 *pu4byteptr = (u32 *)buffer;
+       u32 i, offset, blockcount, remainsize;
+
+       blockcount = size / blocksize;
+       remainsize = size % blocksize;
+
+       for (i = 0; i < blockcount; i++) {
+               offset = i * blocksize;
+               rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
+                               *(pu4byteptr + i));
+       }
+       if (remainsize) {
+               offset = blockcount * blocksize;
+               bufferptr += offset;
+               for (i = 0; i < remainsize; i++) {
+                       rtl_write_byte(rtlpriv,
+                                      (FW_8192C_START_ADDRESS + offset + i),
+                                      *(bufferptr + i));
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(rtl8723_fw_block_write);
+
+void rtl8723_fw_page_write(struct ieee80211_hw *hw,
+                          u32 page, const u8 *buffer, u32 size)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 value8;
+       u8 u8page = (u8) (page & 0x07);
+
+       value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
+
+       rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
+       rtl8723_fw_block_write(hw, buffer, size);
+}
+EXPORT_SYMBOL_GPL(rtl8723_fw_page_write);
+
+static void rtl8723_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
+{
+       u32 fwlen = *pfwlen;
+       u8 remain = (u8) (fwlen % 4);
+
+       remain = (remain == 0) ? 0 : (4 - remain);
+
+       while (remain > 0) {
+               pfwbuf[fwlen] = 0;
+               fwlen++;
+               remain--;
+       }
+       *pfwlen = fwlen;
+}
+
+void rtl8723_write_fw(struct ieee80211_hw *hw,
+                     enum version_8723e version,
+                     u8 *buffer, u32 size)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 *bufferptr = (u8 *)buffer;
+       u32 pagenums, remainsize;
+       u32 page, offset;
+
+       RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
+
+       rtl8723_fill_dummy(bufferptr, &size);
+
+       pagenums = size / FW_8192C_PAGE_SIZE;
+       remainsize = size % FW_8192C_PAGE_SIZE;
+
+       if (pagenums > 8) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Page numbers should not greater then 8\n");
+       }
+       for (page = 0; page < pagenums; page++) {
+               offset = page * FW_8192C_PAGE_SIZE;
+               rtl8723_fw_page_write(hw, page, (bufferptr + offset),
+                                     FW_8192C_PAGE_SIZE);
+       }
+       if (remainsize) {
+               offset = pagenums * FW_8192C_PAGE_SIZE;
+               page = pagenums;
+               rtl8723_fw_page_write(hw, page, (bufferptr + offset),
+                                     remainsize);
+       }
+}
+EXPORT_SYMBOL_GPL(rtl8723_write_fw);
+
+void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
+{
+       u8 u1tmp;
+       u8 delay = 100;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
+       u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+
+       while (u1tmp & BIT(2)) {
+               delay--;
+               if (delay == 0)
+                       break;
+               udelay(50);
+               u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+       }
+       if (delay == 0) {
+               u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+               rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2)));
+       }
+}
+EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset);
+
+void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw)
+{
+       u8 u1b_tmp;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
+
+       u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+       udelay(50);
+
+       u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
+
+       u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "  _8051Reset8723be(): 8051 reset success .\n");
+}
+EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset);
+
+int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int err = -EIO;
+       u32 counter = 0;
+       u32 value32;
+
+       do {
+               value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+       } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
+                (!(value32 & FWDL_CHKSUM_RPT)));
+
+       if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "chksum report fail ! REG_MCUFWDL:0x%08x .\n",
+                        value32);
+               goto exit;
+       }
+       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+                "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
+
+       value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL) | MCUFWDL_RDY;
+       value32 &= ~WINTINI_RDY;
+       rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
+
+       if (is_8723be)
+               rtl8723be_firmware_selfreset(hw);
+       counter = 0;
+
+       do {
+               value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+               if (value32 & WINTINI_RDY) {
+                       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+                                "Polling FW ready success!! "
+                                "REG_MCUFWDL:0x%08x .\n",
+                                value32);
+                       err = 0;
+                       goto exit;
+               }
+               udelay(FW_8192C_POLLING_DELAY);
+
+       } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
+
+       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
+                value32);
+
+exit:
+       return err;
+}
+EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go);
+
+int rtl8723_download_fw(struct ieee80211_hw *hw,
+                       bool is_8723be)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl92c_firmware_header *pfwheader;
+       u8 *pfwdata;
+       u32 fwsize;
+       int err;
+       enum version_8723e version = rtlhal->version;
+
+       if (!rtlhal->pfirmware)
+               return 1;
+
+       pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
+       pfwdata = (u8 *)rtlhal->pfirmware;
+       fwsize = rtlhal->fwsize;
+       RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+                "normal Firmware SIZE %d\n", fwsize);
+
+       if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) {
+               RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+                        "Firmware Version(%d), Signature(%#x), Size(%d)\n",
+                        pfwheader->version, pfwheader->signature,
+                        (int)sizeof(struct rtl92c_firmware_header));
+
+               pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
+               fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
+       }
+       if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
+               rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
+               if (is_8723be)
+                       rtl8723be_firmware_selfreset(hw);
+               else
+                       rtl8723ae_firmware_selfreset(hw);
+       }
+       rtl8723_enable_fw_download(hw, true);
+       rtl8723_write_fw(hw, version, pfwdata, fwsize);
+       rtl8723_enable_fw_download(hw, false);
+
+       err = rtl8723_fw_free_to_go(hw, is_8723be);
+       if (err) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Firmware is not ready to run!\n");
+       } else {
+               RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+                        "Firmware is ready to run!\n");
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8723_download_fw);
+
+bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw,
+                            struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl8192_tx_ring *ring;
+       struct rtl_tx_desc *pdesc;
+       struct sk_buff *pskb = NULL;
+       u8 own;
+       unsigned long flags;
+
+       ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+       pskb = __skb_dequeue(&ring->queue);
+       if (pskb)
+               kfree_skb(pskb);
+
+       spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+       pdesc = &ring->desc[0];
+       own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN);
+
+       rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
+
+       __skb_queue_tail(&ring->queue, skb);
+
+       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+       rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(rtl8723_cmd_send_packet);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h
new file mode 100644 (file)
index 0000000..cf1cc58
--- /dev/null
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __FW_COMMON_H__
+#define __FW_COMMON_H__
+
+#define REG_SYS_FUNC_EN                                0x0002
+#define REG_MCUFWDL                            0x0080
+#define FW_8192C_START_ADDRESS                 0x1000
+#define FW_8192C_PAGE_SIZE                     4096
+#define FW_8192C_POLLING_TIMEOUT_COUNT         6000
+#define FW_8192C_POLLING_DELAY                 5
+
+#define MCUFWDL_RDY                            BIT(1)
+#define FWDL_CHKSUM_RPT                                BIT(2)
+#define WINTINI_RDY                            BIT(6)
+
+#define REG_RSV_CTRL                           0x001C
+#define REG_HMETFR                             0x01CC
+
+enum version_8723e {
+       VERSION_TEST_UMC_CHIP_8723 = 0x0081,
+       VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089,
+       VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089,
+       VERSION_TEST_CHIP_1T1R_8723B = 0x0106,
+       VERSION_NORMAL_SMIC_CHIP_1T1R_8723B = 0x010E,
+       VERSION_UNKNOWN = 0xFF,
+};
+
+enum rtl8723ae_h2c_cmd {
+       H2C_AP_OFFLOAD = 0,
+       H2C_SETPWRMODE = 1,
+       H2C_JOINBSSRPT = 2,
+       H2C_RSVDPAGE = 3,
+       H2C_RSSI_REPORT = 4,
+       H2C_P2P_PS_CTW_CMD = 5,
+       H2C_P2P_PS_OFFLOAD = 6,
+       H2C_RA_MASK = 7,
+       MAX_H2CCMD
+};
+
+enum rtl8723be_cmd {
+       H2C_8723BE_RSVDPAGE = 0,
+       H2C_8723BE_JOINBSSRPT = 1,
+       H2C_8723BE_SCAN = 2,
+       H2C_8723BE_KEEP_ALIVE_CTRL = 3,
+       H2C_8723BE_DISCONNECT_DECISION = 4,
+       H2C_8723BE_INIT_OFFLOAD = 6,
+       H2C_8723BE_AP_OFFLOAD = 8,
+       H2C_8723BE_BCN_RSVDPAGE = 9,
+       H2C_8723BE_PROBERSP_RSVDPAGE = 10,
+
+       H2C_8723BE_SETPWRMODE = 0x20,
+       H2C_8723BE_PS_TUNING_PARA = 0x21,
+       H2C_8723BE_PS_TUNING_PARA2 = 0x22,
+       H2C_8723BE_PS_LPS_PARA = 0x23,
+       H2C_8723BE_P2P_PS_OFFLOAD = 0x24,
+
+       H2C_8723BE_WO_WLAN = 0x80,
+       H2C_8723BE_REMOTE_WAKE_CTRL = 0x81,
+       H2C_8723BE_AOAC_GLOBAL_INFO = 0x82,
+       H2C_8723BE_AOAC_RSVDPAGE = 0x83,
+       H2C_8723BE_RSSI_REPORT = 0x42,
+       H2C_8723BE_RA_MASK = 0x40,
+       H2C_8723BE_SELECTIVE_SUSPEND_ROF_CMD,
+       H2C_8723BE_P2P_PS_MODE,
+       H2C_8723BE_PSD_RESULT,
+       /*Not defined CTW CMD for P2P yet*/
+       H2C_8723BE_P2P_PS_CTW_CMD,
+       MAX_8723BE_H2CCMD
+};
+
+struct rtl92c_firmware_header {
+       u16 signature;
+       u8 category;
+       u8 function;
+       u16 version;
+       u8 subversion;
+       u8 rsvd1;
+       u8 month;
+       u8 date;
+       u8 hour;
+       u8 minute;
+       u16 ramcodesize;
+       u16 rsvd2;
+       u32 svnindex;
+       u32 rsvd3;
+       u32 rsvd4;
+       u32 rsvd5;
+};
+
+void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable);
+void rtl8723_fw_block_write(struct ieee80211_hw *hw,
+                           const u8 *buffer, u32 size);
+void rtl8723_fw_page_write(struct ieee80211_hw *hw,
+                          u32 page, const u8 *buffer, u32 size);
+void rtl8723_write_fw(struct ieee80211_hw *hw,
+                     enum version_8723e version,
+                     u8 *buffer, u32 size);
+int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be);
+int rtl8723_download_fw(struct ieee80211_hw *hw, bool is_8723be);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/main.c b/drivers/net/wireless/rtlwifi/rtl8723com/main.c
new file mode 100644 (file)
index 0000000..9014a94
--- /dev/null
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include <linux/module.h>
+
+
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.Finger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek RTL8723AE/RTL8723BE 802.11n PCI wireless common routines");
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c
new file mode 100644 (file)
index 0000000..d73b659
--- /dev/null
@@ -0,0 +1,434 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "phy_common.h"
+#include "../rtl8723ae/reg.h"
+#include <linux/module.h>
+
+/* These routines are common to RTL8723AE and RTL8723bE */
+
+u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw,
+                            u32 regaddr, u32 bitmask)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 returnvalue, originalvalue, bitshift;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
+       originalvalue = rtl_read_dword(rtlpriv, regaddr);
+       bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+       returnvalue = (originalvalue & bitmask) >> bitshift;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "BBR MASK = 0x%x Addr[0x%x]= 0x%x\n",
+                 bitmask, regaddr, originalvalue);
+
+       return returnvalue;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_query_bb_reg);
+
+void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
+                             u32 bitmask, u32 data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 originalvalue, bitshift;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+                 regaddr, bitmask, data);
+
+       if (bitmask != MASKDWORD) {
+               originalvalue = rtl_read_dword(rtlpriv, regaddr);
+               bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+               data = ((originalvalue & (~bitmask)) | (data << bitshift));
+       }
+
+       rtl_write_dword(rtlpriv, regaddr, data);
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+                 regaddr, bitmask, data);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_set_bb_reg);
+
+u32 rtl8723_phy_calculate_bit_shift(u32 bitmask)
+{
+       u32 i;
+
+       for (i = 0; i <= 31; i++) {
+               if (((bitmask >> i) & 0x1) == 1)
+                       break;
+       }
+       return i;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_calculate_bit_shift);
+
+u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw,
+                              enum radio_path rfpath, u32 offset)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+       u32 newoffset;
+       u32 tmplong, tmplong2;
+       u8 rfpi_enable = 0;
+       u32 retvalue;
+
+       offset &= 0xff;
+       newoffset = offset;
+       if (RT_CANNOT_IO(hw)) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+               return 0xFFFFFFFF;
+       }
+       tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+       if (rfpath == RF90_PATH_A)
+               tmplong2 = tmplong;
+       else
+               tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
+       tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
+                  (newoffset << 23) | BLSSIREADEDGE;
+       rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+                     tmplong & (~BLSSIREADEDGE));
+       mdelay(1);
+       rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
+       mdelay(2);
+       if (rfpath == RF90_PATH_A)
+               rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+                                                BIT(8));
+       else if (rfpath == RF90_PATH_B)
+               rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+                                                BIT(8));
+       if (rfpi_enable)
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
+                                        BLSSIREADBACKDATA);
+       else
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
+                                        BLSSIREADBACKDATA);
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "RFR-%d Addr[0x%x]= 0x%x\n",
+                 rfpath, pphyreg->rf_rb, retvalue);
+       return retvalue;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_rf_serial_read);
+
+void rtl8723_phy_rf_serial_write(struct ieee80211_hw *hw,
+                                enum radio_path rfpath,
+                                u32 offset, u32 data)
+{
+       u32 data_and_addr;
+       u32 newoffset;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+
+       if (RT_CANNOT_IO(hw)) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+               return;
+       }
+       offset &= 0xff;
+       newoffset = offset;
+       data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+       rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "RFW-%d Addr[0x%x]= 0x%x\n", rfpath,
+                  pphyreg->rf3wire_offset, data_and_addr);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_rf_serial_write);
+
+long rtl8723_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+                                 enum wireless_mode wirelessmode,
+                                 u8 txpwridx)
+{
+       long offset;
+       long pwrout_dbm;
+
+       switch (wirelessmode) {
+       case WIRELESS_MODE_B:
+               offset = -7;
+               break;
+       case WIRELESS_MODE_G:
+       case WIRELESS_MODE_N_24G:
+       default:
+               offset = -8;
+               break;
+       }
+       pwrout_dbm = txpwridx / 2 + offset;
+       return pwrout_dbm;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_txpwr_idx_to_dbm);
+
+void rtl8723_phy_init_bb_rf_reg_def(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+       rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+       rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+       rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+       rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+       rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+       rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
+                           RFPGA0_XA_LSSIPARAMETER;
+       rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
+                           RFPGA0_XB_LSSIPARAMETER;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+       rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+       rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+       rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+       rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+       rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+       rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
+       rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+       rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
+       rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
+       rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
+       rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2;
+       rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2;
+       rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
+       rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
+       rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
+       rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
+       rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
+       rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;
+       rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_init_bb_rf_reg_def);
+
+bool rtl8723_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+                                     u32 cmdtableidx,
+                                     u32 cmdtablesz,
+                                     enum swchnlcmd_id cmdid,
+                                     u32 para1, u32 para2,
+                                     u32 msdelay)
+{
+       struct swchnlcmd *pcmd;
+
+       if (cmdtable == NULL) {
+               RT_ASSERT(false, "cmdtable cannot be NULL.\n");
+               return false;
+       }
+
+       if (cmdtableidx >= cmdtablesz)
+               return false;
+
+       pcmd = cmdtable + cmdtableidx;
+       pcmd->cmdid = cmdid;
+       pcmd->para1 = para1;
+       pcmd->para2 = para2;
+       pcmd->msdelay = msdelay;
+       return true;
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_set_sw_chnl_cmdarray);
+
+void rtl8723_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
+                                       bool iqk_ok,
+                                       long result[][8],
+                                       u8 final_candidate,
+                                       bool btxonly)
+{
+       u32 oldval_0, x, tx0_a, reg;
+       long y, tx0_c;
+
+       if (final_candidate == 0xFF) {
+               return;
+       } else if (iqk_ok) {
+               oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+                                         MASKDWORD) >> 22) & 0x3FF;
+               x = result[final_candidate][0];
+               if ((x & 0x00000200) != 0)
+                       x = x | 0xFFFFFC00;
+               tx0_a = (x * oldval_0) >> 8;
+               rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a);
+               rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31),
+                             ((x * oldval_0 >> 7) & 0x1));
+               y = result[final_candidate][1];
+               if ((y & 0x00000200) != 0)
+                       y = y | 0xFFFFFC00;
+               tx0_c = (y * oldval_0) >> 8;
+               rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
+                             ((tx0_c & 0x3C0) >> 6));
+               rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000,
+                             (tx0_c & 0x3F));
+               rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29),
+                             ((y * oldval_0 >> 7) & 0x1));
+               if (btxonly)
+                       return;
+               reg = result[final_candidate][2];
+               rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg);
+               reg = result[final_candidate][3] & 0x3F;
+               rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg);
+               reg = (result[final_candidate][3] >> 6) & 0xF;
+               rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg);
+       }
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_path_a_fill_iqk_matrix);
+
+void rtl8723_save_adda_registers(struct ieee80211_hw *hw, u32 *addareg,
+                                u32 *addabackup, u32 registernum)
+{
+       u32 i;
+
+       for (i = 0; i < registernum; i++)
+               addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
+}
+EXPORT_SYMBOL_GPL(rtl8723_save_adda_registers);
+
+void rtl8723_phy_save_mac_registers(struct ieee80211_hw *hw,
+                                   u32 *macreg, u32 *macbackup)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 i;
+
+       for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+               macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]);
+       macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_save_mac_registers);
+
+void rtl8723_phy_reload_adda_registers(struct ieee80211_hw *hw,
+                                      u32 *addareg, u32 *addabackup,
+                                      u32 regiesternum)
+{
+       u32 i;
+
+       for (i = 0; i < regiesternum; i++)
+               rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_reload_adda_registers);
+
+void rtl8723_phy_reload_mac_registers(struct ieee80211_hw *hw,
+                                     u32 *macreg, u32 *macbackup)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 i;
+
+       for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+               rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]);
+       rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_reload_mac_registers);
+
+void rtl8723_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg,
+                             bool is_patha_on, bool is2t)
+{
+       u32 pathon;
+       u32 i;
+
+       pathon = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
+       if (!is2t) {
+               pathon = 0x0bdb25a0;
+               rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
+       } else {
+               rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon);
+       }
+
+       for (i = 1; i < IQK_ADDA_REG_NUM; i++)
+               rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathon);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_path_adda_on);
+
+void rtl8723_phy_mac_setting_calibration(struct ieee80211_hw *hw,
+                                        u32 *macreg, u32 *macbackup)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 i = 0;
+
+       rtl_write_byte(rtlpriv, macreg[i], 0x3F);
+
+       for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
+               rtl_write_byte(rtlpriv, macreg[i],
+                              (u8) (macbackup[i] & (~BIT(3))));
+       rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5))));
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_mac_setting_calibration);
+
+void rtl8723_phy_path_a_standby(struct ieee80211_hw *hw)
+{
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
+       rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_path_a_standby);
+
+void rtl8723_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode)
+{
+       u32 mode;
+
+       mode = pi_mode ? 0x01000100 : 0x01000000;
+       rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
+       rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
+}
+EXPORT_SYMBOL_GPL(rtl8723_phy_pi_mode_switch);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h
new file mode 100644 (file)
index 0000000..83b891a
--- /dev/null
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __PHY_COMMON__
+#define __PHY_COMMON__
+
+#define RT_CANNOT_IO(hw)                       false
+
+enum swchnlcmd_id {
+       CMDID_END,
+       CMDID_SET_TXPOWEROWER_LEVEL,
+       CMDID_BBREGWRITE10,
+       CMDID_WRITEPORT_ULONG,
+       CMDID_WRITEPORT_USHORT,
+       CMDID_WRITEPORT_UCHAR,
+       CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+       enum swchnlcmd_id cmdid;
+       u32 para1;
+       u32 para2;
+       u32 msdelay;
+};
+
+u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw,
+                            u32 regaddr, u32 bitmask);
+void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
+                             u32 bitmask, u32 data);
+u32 rtl8723_phy_calculate_bit_shift(u32 bitmask);
+u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw,
+                              enum radio_path rfpath, u32 offset);
+void rtl8723_phy_rf_serial_write(struct ieee80211_hw *hw,
+                                enum radio_path rfpath,
+                                u32 offset, u32 data);
+long rtl8723_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+                                 enum wireless_mode wirelessmode,
+                                 u8 txpwridx);
+void rtl8723_phy_init_bb_rf_reg_def(struct ieee80211_hw *hw);
+bool rtl8723_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+                                     u32 cmdtableidx,
+                                     u32 cmdtablesz,
+                                     enum swchnlcmd_id cmdid,
+                                     u32 para1, u32 para2,
+                                     u32 msdelay);
+void rtl8723_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
+                                       bool iqk_ok,
+                                       long result[][8],
+                                       u8 final_candidate,
+                                       bool btxonly);
+void rtl8723_save_adda_registers(struct ieee80211_hw *hw, u32 *addareg,
+                                u32 *addabackup, u32 registernum);
+void rtl8723_phy_save_mac_registers(struct ieee80211_hw *hw,
+                                   u32 *macreg, u32 *macbackup);
+void rtl8723_phy_reload_adda_registers(struct ieee80211_hw *hw,
+                                      u32 *addareg, u32 *addabackup,
+                                      u32 regiesternum);
+void rtl8723_phy_reload_mac_registers(struct ieee80211_hw *hw,
+                                     u32 *macreg, u32 *macbackup);
+void rtl8723_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg,
+                             bool is_patha_on, bool is2t);
+void rtl8723_phy_mac_setting_calibration(struct ieee80211_hw *hw,
+                                        u32 *macreg, u32 *macbackup);
+void rtl8723_phy_path_a_standby(struct ieee80211_hw *hw);
+void rtl8723_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode);
+
+#endif
index 4933f02ce1d510cf94ef127b59ea025238ad9476..0398d3ea15b00b6c68b4b1e160700df276f90254 100644 (file)
@@ -410,7 +410,7 @@ static void rtl_usb_init_sw(struct ieee80211_hw *hw)
        mac->current_ampdu_factor = 3;
 
        /* QOS */
-       rtlusb->acm_method = eAcmWay2_SW;
+       rtlusb->acm_method = EACMWAY2_SW;
 
        /* IRQ */
        /* HIMR - turn all on */
@@ -994,7 +994,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw,
                seq_number += 1;
                seq_number <<= 4;
        }
-       rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, sta, skb,
+       rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, NULL, info, sta, skb,
                                        hw_queue, &tcb_desc);
        if (!ieee80211_has_morefrags(hdr->frame_control)) {
                if (qc)
index 8c647391bedf0f4bc5ef4fca39b7ca39a05e1483..6965afdf572a9d57c06fabd8b070fbc8cc58b9ce 100644 (file)
 #include <linux/completion.h>
 #include "debug.h"
 
+#define        MASKBYTE0                               0xff
+#define        MASKBYTE1                               0xff00
+#define        MASKBYTE2                               0xff0000
+#define        MASKBYTE3                               0xff000000
+#define        MASKHWORD                               0xffff0000
+#define        MASKLWORD                               0x0000ffff
+#define        MASKDWORD                               0xffffffff
+#define        MASK12BITS                              0xfff
+#define        MASKH4BITS                              0xf0000000
+#define MASKOFDM_D                             0xffc00000
+#define        MASKCCK                                 0x3f3f3f3f
+
+#define        MASK4BITS                               0x0f
+#define        MASK20BITS                              0xfffff
+#define RFREG_OFFSET_MASK                      0xfffff
+
+#define        MASKBYTE0                               0xff
+#define        MASKBYTE1                               0xff00
+#define        MASKBYTE2                               0xff0000
+#define        MASKBYTE3                               0xff000000
+#define        MASKHWORD                               0xffff0000
+#define        MASKLWORD                               0x0000ffff
+#define        MASKDWORD                               0xffffffff
+#define        MASK12BITS                              0xfff
+#define        MASKH4BITS                              0xf0000000
+#define MASKOFDM_D                             0xffc00000
+#define        MASKCCK                                 0x3f3f3f3f
+
+#define        MASK4BITS                               0x0f
+#define        MASK20BITS                              0xfffff
+#define RFREG_OFFSET_MASK                      0xfffff
+
 #define RF_CHANGE_BY_INIT                      0
 #define RF_CHANGE_BY_IPS                       BIT(28)
 #define RF_CHANGE_BY_PS                                BIT(29)
@@ -49,6 +81,7 @@
 
 #define IQK_ADDA_REG_NUM                       16
 #define IQK_MAC_REG_NUM                                4
+#define IQK_THRESHOLD                          8
 
 #define MAX_KEY_LEN                            61
 #define KEY_BUF_SIZE                           5
 #define MAC80211_4ADDR_LEN                     30
 
 #define CHANNEL_MAX_NUMBER     (14 + 24 + 21)  /* 14 is the max channel no */
+#define CHANNEL_MAX_NUMBER_2G          14
+#define CHANNEL_MAX_NUMBER_5G          54 /* Please refer to
+                                           *"phy_GetChnlGroup8812A" and
+                                           * "Hal_ReadTxPowerInfo8812A"
+                                           */
+#define CHANNEL_MAX_NUMBER_5G_80M      7
 #define CHANNEL_GROUP_MAX      (3 + 9) /*  ch1~3, 4~9, 10~14 = three groups */
+#define CHANNEL_MAX_NUMBER_5G          54 /* Please refer to
+                                           *"phy_GetChnlGroup8812A" and
+                                           * "Hal_ReadTxPowerInfo8812A"
+                                           */
+#define CHANNEL_MAX_NUMBER_5G_80M      7
 #define MAX_PG_GROUP                   13
 #define        CHANNEL_GROUP_MAX_2G            3
 #define        CHANNEL_GROUP_IDX_5GL           3
 #define CHANNEL_MAX_NUMBER_2G          14
 #define AVG_THERMAL_NUM                        8
 #define AVG_THERMAL_NUM_88E            4
+#define AVG_THERMAL_NUM_8723BE         4
 #define MAX_TID_COUNT                  9
 
 /* for early mode */
 #define        MAX_CHNL_GROUP_24G              6
 #define        MAX_CHNL_GROUP_5G               14
 
+#define TX_PWR_BY_RATE_NUM_BAND                2
+#define TX_PWR_BY_RATE_NUM_RF          4
+#define TX_PWR_BY_RATE_NUM_SECTION     12
+#define MAX_BASE_NUM_IN_PHY_REG_PG_24G  6
+#define MAX_BASE_NUM_IN_PHY_REG_PG_5G  5
+
+#define RTL8192EE_SEG_NUM              1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */
+
+#define DEL_SW_IDX_SZ          30
+#define BAND_NUM                       3
+
+enum rf_tx_num {
+       RF_1TX = 0,
+       RF_2TX,
+       RF_MAX_TX_NUM,
+       RF_TX_NUM_NONIMPLEMENT,
+};
+
 struct txpower_info_2g {
        u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
        u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
@@ -115,6 +178,8 @@ struct txpower_info_2g {
        u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
        u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
        u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT];
 };
 
 struct txpower_info_5g {
@@ -123,6 +188,17 @@ struct txpower_info_5g {
        u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
        u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
        u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
+enum rate_section {
+       CCK = 0,
+       OFDM,
+       HT_MCS0_MCS7,
+       HT_MCS8_MCS15,
+       VHT_1SSMCS0_1SSMCS9,
+       VHT_2SSMCS0_2SSMCS9,
 };
 
 enum intf_type {
@@ -158,7 +234,10 @@ enum hardware_type {
        HARDWARE_TYPE_RTL8192DU,
        HARDWARE_TYPE_RTL8723AE,
        HARDWARE_TYPE_RTL8723U,
+       HARDWARE_TYPE_RTL8723BE,
        HARDWARE_TYPE_RTL8188EE,
+       HARDWARE_TYPE_RTL8821AE,
+       HARDWARE_TYPE_RTL8812AE,
 
        /* keep it last */
        HARDWARE_TYPE_NUM
@@ -195,8 +274,16 @@ enum hardware_type {
         _pdesc->rxmcs == DESC92_RATE5_5M ||            \
         _pdesc->rxmcs == DESC92_RATE11M)
 
+#define RTL8723E_RX_HAL_IS_CCK_RATE(rxmcs)             \
+       ((rxmcs) == DESC92_RATE1M ||                    \
+        (rxmcs) == DESC92_RATE2M ||                    \
+        (rxmcs) == DESC92_RATE5_5M ||                  \
+        (rxmcs) == DESC92_RATE11M)
+
 enum scan_operation_backup_opt {
        SCAN_OPT_BACKUP = 0,
+       SCAN_OPT_BACKUP_BAND0 = 0,
+       SCAN_OPT_BACKUP_BAND1,
        SCAN_OPT_RESTORE,
        SCAN_OPT_MAX
 };
@@ -231,7 +318,9 @@ struct bb_reg_def {
 
 enum io_type {
        IO_CMD_PAUSE_DM_BY_SCAN = 0,
-       IO_CMD_RESUME_DM_BY_SCAN = 1,
+       IO_CMD_PAUSE_BAND0_DM_BY_SCAN = 0,
+       IO_CMD_PAUSE_BAND1_DM_BY_SCAN = 1,
+       IO_CMD_RESUME_DM_BY_SCAN = 2,
 };
 
 enum hw_variables {
@@ -298,6 +387,7 @@ enum hw_variables {
        HW_VAR_SET_RPWM,
        HW_VAR_H2C_FW_PWRMODE,
        HW_VAR_H2C_FW_JOINBSSRPT,
+       HW_VAR_H2C_FW_MEDIASTATUSRPT,
        HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
        HW_VAR_FW_PSMODE_STATUS,
        HW_VAR_RESUME_CLK_ON,
@@ -330,6 +420,8 @@ enum hw_variables {
 
        HAL_DEF_WOWLAN,
        HW_VAR_MRC,
+       HW_VAR_KEEP_ALIVE,
+       HW_VAR_NAV_UPPER,
 
        HW_VAR_MGT_FILTER,
        HW_VAR_CTRL_FILTER,
@@ -348,34 +440,34 @@ enum rt_oem_id {
        RT_CID_8187_HW_LED = 3,
        RT_CID_8187_NETGEAR = 4,
        RT_CID_WHQL = 5,
-       RT_CID_819x_CAMEO = 6,
-       RT_CID_819x_RUNTOP = 7,
-       RT_CID_819x_Senao = 8,
+       RT_CID_819X_CAMEO = 6,
+       RT_CID_819X_RUNTOP = 7,
+       RT_CID_819X_SENAO = 8,
        RT_CID_TOSHIBA = 9,
-       RT_CID_819x_Netcore = 10,
-       RT_CID_Nettronix = 11,
+       RT_CID_819X_NETCORE = 10,
+       RT_CID_NETTRONIX = 11,
        RT_CID_DLINK = 12,
        RT_CID_PRONET = 13,
        RT_CID_COREGA = 14,
-       RT_CID_819x_ALPHA = 15,
-       RT_CID_819x_Sitecom = 16,
+       RT_CID_819X_ALPHA = 15,
+       RT_CID_819X_SITECOM = 16,
        RT_CID_CCX = 17,
-       RT_CID_819x_Lenovo = 18,
-       RT_CID_819x_QMI = 19,
-       RT_CID_819x_Edimax_Belkin = 20,
-       RT_CID_819x_Sercomm_Belkin = 21,
-       RT_CID_819x_CAMEO1 = 22,
-       RT_CID_819x_MSI = 23,
-       RT_CID_819x_Acer = 24,
-       RT_CID_819x_HP = 27,
-       RT_CID_819x_CLEVO = 28,
-       RT_CID_819x_Arcadyan_Belkin = 29,
-       RT_CID_819x_SAMSUNG = 30,
-       RT_CID_819x_WNC_COREGA = 31,
-       RT_CID_819x_Foxcoon = 32,
-       RT_CID_819x_DELL = 33,
-       RT_CID_819x_PRONETS = 34,
-       RT_CID_819x_Edimax_ASUS = 35,
+       RT_CID_819X_LENOVO = 18,
+       RT_CID_819X_QMI = 19,
+       RT_CID_819X_EDIMAX_BELKIN = 20,
+       RT_CID_819X_SERCOMM_BELKIN = 21,
+       RT_CID_819X_CAMEO1 = 22,
+       RT_CID_819X_MSI = 23,
+       RT_CID_819X_ACER = 24,
+       RT_CID_819X_HP = 27,
+       RT_CID_819X_CLEVO = 28,
+       RT_CID_819X_ARCADYAN_BELKIN = 29,
+       RT_CID_819X_SAMSUNG = 30,
+       RT_CID_819X_WNC_COREGA = 31,
+       RT_CID_819X_FOXCOON = 32,
+       RT_CID_819X_DELL = 33,
+       RT_CID_819X_PRONETS = 34,
+       RT_CID_819X_EDIMAX_ASUS = 35,
        RT_CID_NETGEAR = 36,
        RT_CID_PLANEX = 37,
        RT_CID_CC_C = 38,
@@ -389,6 +481,7 @@ enum hw_descs {
        HW_DESC_RXBUFF_ADDR,
        HW_DESC_RXPKT_LEN,
        HW_DESC_RXERO,
+       HW_DESC_RX_PREPARE,
 };
 
 enum prime_sc {
@@ -407,6 +500,7 @@ enum rf_type {
 enum ht_channel_width {
        HT_CHANNEL_WIDTH_20 = 0,
        HT_CHANNEL_WIDTH_20_40 = 1,
+       HT_CHANNEL_WIDTH_80 = 2,
 };
 
 /* Ref: 802.11i sepc D10.0 7.3.2.25.1
@@ -471,6 +565,9 @@ enum rtl_var_map {
        MAC_RCR_ACRC32,
        MAC_RCR_ACF,
        MAC_RCR_AAP,
+       MAC_HIMR,
+       MAC_HIMRE,
+       MAC_HSISR,
 
        /*efuse map */
        EFUSE_TEST,
@@ -608,7 +705,7 @@ enum rtl_led_pin {
 enum acm_method {
        eAcmWay0_SwAndHw = 0,
        eAcmWay1_HW = 1,
-       eAcmWay2_SW = 2,
+       EACMWAY2_SW = 2,
 };
 
 enum macphy_mode {
@@ -645,7 +742,9 @@ enum wireless_mode {
        WIRELESS_MODE_G = 0x04,
        WIRELESS_MODE_AUTO = 0x08,
        WIRELESS_MODE_N_24G = 0x10,
-       WIRELESS_MODE_N_5G = 0x20
+       WIRELESS_MODE_N_5G = 0x20,
+       WIRELESS_MODE_AC_5G = 0x40,
+       WIRELESS_MODE_AC_24G  = 0x80
 };
 
 #define IS_WIRELESS_MODE_A(wirelessmode)       \
@@ -669,6 +768,8 @@ enum ratr_table_mode {
        RATR_INX_WIRELESS_B = 6,
        RATR_INX_WIRELESS_MC = 7,
        RATR_INX_WIRELESS_A = 8,
+       RATR_INX_WIRELESS_AC_5N = 8,
+       RATR_INX_WIRELESS_AC_24N = 9,
 };
 
 enum rtl_link_state {
@@ -803,8 +904,12 @@ struct wireless_stats {
        long signal_strength;
 
        u8 rx_rssi_percentage[4];
+       u8 rx_evm_dbm[4];
        u8 rx_evm_percentage[2];
 
+       u16 rx_cfo_short[4];
+       u16 rx_cfo_tail[4];
+
        struct rt_smooth_data ui_rssi;
        struct rt_smooth_data ui_link_quality;
 };
@@ -817,9 +922,9 @@ struct rate_adaptive {
        u32 high_rssi_thresh_for_ra;
        u32 high2low_rssi_thresh_for_ra;
        u8 low2high_rssi_thresh_for_ra40m;
-       u32 low_rssi_thresh_for_ra40M;
+       u32 low_rssi_thresh_for_ra40m;
        u8 low2high_rssi_thresh_for_ra20m;
-       u32 low_rssi_thresh_for_ra20M;
+       u32 low_rssi_thresh_for_ra20m;
        u32 upper_rssi_threshold_ratr;
        u32 middleupper_rssi_threshold_ratr;
        u32 middle_rssi_threshold_ratr;
@@ -833,6 +938,10 @@ struct rate_adaptive {
        u32 ping_rssi_thresh_for_ra;
        u32 last_ratr;
        u8 pre_ratr_state;
+       u8 ldpc_thres;
+       bool use_ldpc;
+       bool lower_rts_rate;
+       bool is_special_data;
 };
 
 struct regd_pair_mapping {
@@ -841,6 +950,16 @@ struct regd_pair_mapping {
        u16 reg_2ghz_ctl;
 };
 
+struct dynamic_primary_cca {
+       u8 pricca_flag;
+       u8 intf_flag;
+       u8 intf_type;
+       u8 dup_rts_flag;
+       u8 monitor_flag;
+       u8 ch_offset;
+       u8 mf_state;
+};
+
 struct rtl_regulatory {
        char alpha2[2];
        u16 country_code;
@@ -976,16 +1095,29 @@ struct rtl_phy {
        u32 iqk_bb_backup[10];
        bool iqk_initialized;
 
+       bool rfpath_rx_enable[MAX_RF_PATH];
+       u8 reg_837;
        /* Dual mac */
        bool need_iqk;
        struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM];
 
        bool rfpi_enable;
+       bool iqk_in_progress;
 
        u8 pwrgroup_cnt;
        u8 cck_high_power;
        /* MAX_PG_GROUP groups of pwr diff by rates */
        u32 mcs_offset[MAX_PG_GROUP][16];
+       u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND]
+                                  [TX_PWR_BY_RATE_NUM_RF]
+                                  [TX_PWR_BY_RATE_NUM_RF]
+                                  [TX_PWR_BY_RATE_NUM_SECTION];
+       u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF]
+                                [TX_PWR_BY_RATE_NUM_RF]
+                                [MAX_BASE_NUM_IN_PHY_REG_PG_24G];
+       u8 txpwr_by_rate_base_5g[TX_PWR_BY_RATE_NUM_RF]
+                               [TX_PWR_BY_RATE_NUM_RF]
+                               [MAX_BASE_NUM_IN_PHY_REG_PG_5G];
        u8 default_initialgain[4];
 
        /* the current Tx power level */
@@ -998,6 +1130,7 @@ struct rtl_phy {
        bool apk_done;
        u32 reg_rf3c[2];        /* pathA / pathB  */
 
+       u32 backup_rf_0x1a;/*92ee*/
        /* bfsync */
        u8 framesync;
        u32 framesync_c34;
@@ -1006,6 +1139,7 @@ struct rtl_phy {
        struct phy_parameters hwparam_tables[MAX_TAB];
        u16 rf_pathmap;
 
+       u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/
        enum rt_polarity_ctl polarity_ctl;
 };
 
@@ -1133,6 +1267,7 @@ struct rtl_mac {
        u8 use_cts_protect;
        u8 cur_40_prime_sc;
        u8 cur_40_prime_sc_bk;
+       u8 cur_80_prime_sc;
        u64 tsf;
        u8 retry_short;
        u8 retry_long;
@@ -1213,6 +1348,7 @@ struct rtl_hal {
        bool being_init_adapter;
        bool bbrf_ready;
        bool mac_func_enable;
+       bool pre_edcca_enable;
        struct bt_coexist_8723 hal_coex_8723;
 
        enum intf_type interface;
@@ -1234,6 +1370,7 @@ struct rtl_hal {
        /*Reserve page start offset except beacon in TxQ. */
        u8 fw_rsvdpage_startoffset;
        u8 h2c_txcmd_seq;
+       u8 current_ra_rate;
 
        /* FW Cmd IO related */
        u16 fwcmd_iomap;
@@ -1273,6 +1410,9 @@ struct rtl_hal {
        bool disable_amsdu_8k;
        bool master_of_dmsp;
        bool slave_of_dmsp;
+
+       u16 rx_tag;/*for 92ee*/
+       u8 rts_en;
 };
 
 struct rtl_security {
@@ -1321,6 +1461,16 @@ struct fast_ant_training {
        bool    becomelinked;
 };
 
+struct dm_phy_dbg_info {
+       char rx_snrdb[4];
+       u64 num_qry_phy_status;
+       u64 num_qry_phy_status_cck;
+       u64 num_qry_phy_status_ofdm;
+       u16 num_qry_beacon_pkt;
+       u16 num_non_be_pkt;
+       s32 rx_evm[4];
+};
+
 struct rtl_dm {
        /*PHY status for Dynamic Management */
        long entry_min_undec_sm_pwdb;
@@ -1360,29 +1510,84 @@ struct rtl_dm {
        u8 txpower_track_control;
        bool interrupt_migration;
        bool disable_tx_int;
-       char ofdm_index[2];
+       char ofdm_index[MAX_RF_PATH];
+       u8 default_ofdm_index;
+       u8 default_cck_index;
        char cck_index;
-       char delta_power_index;
-       char delta_power_index_last;
-       char power_index_offset;
+       char delta_power_index[MAX_RF_PATH];
+       char delta_power_index_last[MAX_RF_PATH];
+       char power_index_offset[MAX_RF_PATH];
+       char absolute_ofdm_swing_idx[MAX_RF_PATH];
+       char remnant_ofdm_swing_idx[MAX_RF_PATH];
+       char remnant_cck_idx;
+       bool modify_txagc_flag_path_a;
+       bool modify_txagc_flag_path_b;
+
+       bool one_entry_only;
+       struct dm_phy_dbg_info dbginfo;
+
+       /* Dynamic ATC switch */
+       bool atc_status;
+       bool large_cfo_hit;
+       bool is_freeze;
+       int cfo_tail[2];
+       int cfo_ave_pre;
+       int crystal_cap;
+       u8 cfo_threshold;
+       u32 packet_count;
+       u32 packet_count_pre;
+       u8 tx_rate;
 
        /*88e tx power tracking*/
-       u8      swing_idx_ofdm[2];
+       u8      swing_idx_ofdm[MAX_RF_PATH];
        u8      swing_idx_ofdm_cur;
-       u8      swing_idx_ofdm_base;
+       u8      swing_idx_ofdm_base[MAX_RF_PATH];
        bool    swing_flag_ofdm;
        u8      swing_idx_cck;
        u8      swing_idx_cck_cur;
        u8      swing_idx_cck_base;
        bool    swing_flag_cck;
 
+       char    swing_diff_2g;
+       char    swing_diff_5g;
+
+       u8 delta_swing_table_idx_24gccka_p[DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_24gccka_n[DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_24gcckb_p[DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_24gcckb_n[DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_24ga_p[DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_24ga_n[DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_24gb_p[DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_24gb_n[DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_5ga_p[BAND_NUM][DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_5ga_n[BAND_NUM][DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_5gb_p[BAND_NUM][DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_5gb_n[BAND_NUM][DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_24ga_p_8188e[DEL_SW_IDX_SZ];
+       u8 delta_swing_table_idx_24ga_n_8188e[DEL_SW_IDX_SZ];
+
        /* DMSP */
        bool supp_phymode_switch;
 
+       /* DulMac */
        struct fast_ant_training fat_table;
+
+       u8      resp_tx_path;
+       u8      path_sel;
+       u32     patha_sum;
+       u32     pathb_sum;
+       u32     patha_cnt;
+       u32     pathb_cnt;
+
+       u8 pre_channel;
+       u8 *p_channel;
+       u8 linked_interval;
+
+       u64 last_tx_ok_cnt;
+       u64 last_rx_ok_cnt;
 };
 
-#define        EFUSE_MAX_LOGICAL_SIZE                  256
+#define        EFUSE_MAX_LOGICAL_SIZE                  512
 
 struct rtl_efuse {
        bool autoLoad_ok;
@@ -1422,12 +1627,9 @@ struct rtl_efuse {
        u8 eeprom_tssi_5g[3][2]; /* for 5GL/5GM/5GH band. */
        u8 eeprom_pwrlimit_ht20[CHANNEL_GROUP_MAX];
        u8 eeprom_pwrlimit_ht40[CHANNEL_GROUP_MAX];
-       u8 eeprom_chnlarea_txpwr_cck[2][CHANNEL_GROUP_MAX_2G];
-       u8 eeprom_chnlarea_txpwr_ht40_1s[2][CHANNEL_GROUP_MAX];
-       u8 eprom_chnl_txpwr_ht40_2sdf[2][CHANNEL_GROUP_MAX];
-       u8 txpwrlevel_cck[2][CHANNEL_MAX_NUMBER_2G];
-       u8 txpwrlevel_ht40_1s[2][CHANNEL_MAX_NUMBER];   /*For HT 40MHZ pwr */
-       u8 txpwrlevel_ht40_2s[2][CHANNEL_MAX_NUMBER];   /*For HT 40MHZ pwr */
+       u8 eeprom_chnlarea_txpwr_cck[MAX_RF_PATH][CHANNEL_GROUP_MAX_2G];
+       u8 eeprom_chnlarea_txpwr_ht40_1s[MAX_RF_PATH][CHANNEL_GROUP_MAX];
+       u8 eprom_chnl_txpwr_ht40_2sdf[MAX_RF_PATH][CHANNEL_GROUP_MAX];
 
        u8 internal_pa_5g[2];   /* pathA / pathB */
        u8 eeprom_c9;
@@ -1438,9 +1640,38 @@ struct rtl_efuse {
        u8 pwrgroup_ht20[2][CHANNEL_MAX_NUMBER];
        u8 pwrgroup_ht40[2][CHANNEL_MAX_NUMBER];
 
-       char txpwr_ht20diff[2][CHANNEL_MAX_NUMBER]; /*HT 20<->40 Pwr diff */
-       /*For HT<->legacy pwr diff*/
-       u8 txpwr_legacyhtdiff[2][CHANNEL_MAX_NUMBER];
+       u8 txpwrlevel_cck[MAX_RF_PATH][CHANNEL_MAX_NUMBER_2G];
+       /*For HT 40MHZ pwr */
+       u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       /*For HT 40MHZ pwr */
+       u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+
+       /*--------------------------------------------------------*
+        * 8192CE\8192SE\8192DE\8723AE use the following 4 arrays,
+        * other ICs (8188EE\8723BE\8192EE\8812AE...)
+        * define new arrays in Windows code.
+        * BUT, in linux code, we use the same array for all ICs.
+        *
+        * The Correspondance relation between two arrays is:
+        * txpwr_cckdiff[][] == CCK_24G_Diff[][]
+        * txpwr_ht20diff[][] == BW20_24G_Diff[][]
+        * txpwr_ht40diff[][] == BW40_24G_Diff[][]
+        * txpwr_legacyhtdiff[][] == OFDM_24G_Diff[][]
+        *
+        * Sizes of these arrays are decided by the larger ones.
+        */
+       char txpwr_cckdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       char txpwr_ht20diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       char txpwr_ht40diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       char txpwr_legacyhtdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+
+       u8 txpwr_5g_bw40base[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       u8 txpwr_5g_bw80base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M];
+       char txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT];
+       char txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT];
+       char txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT];
+       char txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT];
+
        u8 txpwr_safetyflag;                    /* Band edge enable flag */
        u16 eeprom_txpowerdiff;
        u8 legacy_httxpowerdiff;        /* Legacy to HT rate power diff */
@@ -1571,7 +1802,9 @@ struct rtl_stats {
        bool rx_is40Mhzpacket;
        u32 rx_pwdb_all;
        u8 rx_mimo_signalstrength[4];   /*in 0~100 index */
-       s8 rx_mimo_sig_qual[2];
+       s8 rx_mimo_sig_qual[4];
+       u8 rx_pwr[4]; /* per-path's pwdb */
+       u8 rx_snr[4]; /* per-path's SNR */
        bool packet_matchbssid;
        bool is_cck;
        bool is_ht;
@@ -1644,6 +1877,8 @@ struct rtl_tcb_desc {
        bool btx_enable_sw_calc_duration;
 };
 
+struct rtl92c_firmware_header;
+
 struct rtl_hal_ops {
        int (*init_sw_vars) (struct ieee80211_hw *hw);
        void (*deinit_sw_vars) (struct ieee80211_hw *hw);
@@ -1673,9 +1908,17 @@ struct rtl_hal_ops {
        void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val);
        void (*update_rate_tbl) (struct ieee80211_hw *hw,
                              struct ieee80211_sta *sta, u8 rssi_level);
+       void (*pre_fill_tx_bd_desc)(struct ieee80211_hw *hw, u8 *tx_bd_desc,
+                                   u8 *desc, u8 queue_index,
+                                   struct sk_buff *skb, dma_addr_t addr);
        void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level);
+       u16 (*rx_desc_buff_remained_cnt)(struct ieee80211_hw *hw,
+                                        u8 queue_index);
+       void (*rx_check_dma_ok)(struct ieee80211_hw *hw, u8 *header_desc,
+                               u8 queue_index);
        void (*fill_tx_desc) (struct ieee80211_hw *hw,
                              struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+                             u8 *pbd_desc_tx,
                              struct ieee80211_tx_info *info,
                              struct ieee80211_sta *sta,
                              struct sk_buff *skb, u8 hw_queue,
@@ -1698,8 +1941,11 @@ struct rtl_hal_ops {
                                    enum rf_pwrstate rfpwr_state);
        void (*led_control) (struct ieee80211_hw *hw,
                             enum led_ctl_mode ledaction);
-       void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+       void (*set_desc)(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                        u8 desc_name, u8 *val);
        u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name);
+       bool (*is_tx_desc_closed) (struct ieee80211_hw *hw,
+                                  u8 hw_queue, u16 index);
        void (*tx_polling) (struct ieee80211_hw *hw, u8 hw_queue);
        void (*enable_hw_sec) (struct ieee80211_hw *hw);
        void (*set_key) (struct ieee80211_hw *hw, u32 key_index,
@@ -1738,6 +1984,10 @@ struct rtl_hal_ops {
        void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw);
        void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id,
                              u32 cmd_len, u8 *p_cmdbuffer);
+       bool (*get_btc_status) (void);
+       bool (*is_fw_header) (struct rtl92c_firmware_header *hdr);
+       u32 (*rx_command_packet)(struct ieee80211_hw *hw,
+                                struct rtl_stats status, struct sk_buff *skb);
 };
 
 struct rtl_intf_ops {
@@ -1847,6 +2097,8 @@ struct rtl_locks {
 
        /*Easy concurrent*/
        spinlock_t check_sendpkt_lock;
+
+       spinlock_t iqk_lock;
 };
 
 struct rtl_works {
@@ -1915,6 +2167,7 @@ struct ps_t {
        u8 cur_ccasate;
        u8 pre_rfstate;
        u8 cur_rfstate;
+       u8 initialize;
        long rssi_val_min;
 };
 
@@ -1939,6 +2192,7 @@ struct dig_t {
        u8 cursta_cstate;
        u8 presta_cstate;
        u8 curmultista_cstate;
+       u8 stop_dig;
        char back_val;
        char back_range_max;
        char back_range_min;
@@ -1956,6 +2210,7 @@ struct dig_t {
        u8 cur_ccasate;
        u8 large_fa_hit;
        u8 dig_dynamic_min;
+       u8 dig_dynamic_min_1;
        u8 forbidden_igi;
        u8 dig_state;
        u8 dig_highpwrstate;
@@ -1972,6 +2227,7 @@ struct dig_t {
        char backoffval_range_min;
        u8 dig_min_0;
        u8 dig_min_1;
+       u8 bt30_cur_igi;
        bool media_connect_0;
        bool media_connect_1;
 
@@ -1986,6 +2242,96 @@ struct rtl_global_var {
        spinlock_t glb_list_lock;
 };
 
+struct rtl_btc_info {
+       u8 bt_type;
+       u8 btcoexist;
+       u8 ant_num;
+};
+
+struct bt_coexist_info {
+       struct rtl_btc_ops *btc_ops;
+       struct rtl_btc_info btc_info;
+       /* EEPROM BT info. */
+       u8 eeprom_bt_coexist;
+       u8 eeprom_bt_type;
+       u8 eeprom_bt_ant_num;
+       u8 eeprom_bt_ant_isol;
+       u8 eeprom_bt_radio_shared;
+
+       u8 bt_coexistence;
+       u8 bt_ant_num;
+       u8 bt_coexist_type;
+       u8 bt_state;
+       u8 bt_cur_state;        /* 0:on, 1:off */
+       u8 bt_ant_isolation;    /* 0:good, 1:bad */
+       u8 bt_pape_ctrl;        /* 0:SW, 1:SW/HW dynamic */
+       u8 bt_service;
+       u8 bt_radio_shared_type;
+       u8 bt_rfreg_origin_1e;
+       u8 bt_rfreg_origin_1f;
+       u8 bt_rssi_state;
+       u32 ratio_tx;
+       u32 ratio_pri;
+       u32 bt_edca_ul;
+       u32 bt_edca_dl;
+
+       bool init_set;
+       bool bt_busy_traffic;
+       bool bt_traffic_mode_set;
+       bool bt_non_traffic_mode_set;
+
+       bool fw_coexist_all_off;
+       bool sw_coexist_all_off;
+       bool hw_coexist_all_off;
+       u32 cstate;
+       u32 previous_state;
+       u32 cstate_h;
+       u32 previous_state_h;
+
+       u8 bt_pre_rssi_state;
+       u8 bt_pre_rssi_state1;
+
+       u8 reg_bt_iso;
+       u8 reg_bt_sco;
+       bool balance_on;
+       u8 bt_active_zero_cnt;
+       bool cur_bt_disabled;
+       bool pre_bt_disabled;
+
+       u8 bt_profile_case;
+       u8 bt_profile_action;
+       bool bt_busy;
+       bool hold_for_bt_operation;
+       u8 lps_counter;
+};
+
+struct rtl_btc_ops {
+       void (*btc_init_variables) (struct rtl_priv *rtlpriv);
+       void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv);
+       void (*btc_init_hw_config) (struct rtl_priv *rtlpriv);
+       void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type);
+       void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype);
+       void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action);
+       void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv,
+                                       enum _RT_MEDIA_STATUS mstatus);
+       void (*btc_periodical) (struct rtl_priv *rtlpriv);
+       void (*btc_halt_notify) (void);
+       void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv,
+                                  u8 *tmp_buf, u8 length);
+       bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv);
+       bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv);
+       bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv);
+};
+
+struct proxim {
+       bool proxim_on;
+
+       void *proximity_priv;
+       int (*proxim_rx)(struct ieee80211_hw *hw, struct rtl_stats *status,
+                        struct sk_buff *skb);
+       u8  (*proxim_get_var)(struct ieee80211_hw *hw, u8 type);
+};
+
 struct rtl_priv {
        struct ieee80211_hw *hw;
        struct completion firmware_loading_complete;
@@ -2008,6 +2354,7 @@ struct rtl_priv {
 
        struct rtl_ps_ctl psc;
        struct rate_adaptive ra;
+       struct dynamic_primary_cca primarycca;
        struct wireless_stats stats;
        struct rt_link_detect link_info;
        struct false_alarm_statistics falsealm_cnt;
@@ -2048,6 +2395,20 @@ struct rtl_priv {
        bool enter_ps;  /* true when entering PS */
        u8 rate_mask[5];
 
+       /* intel Proximity, should be alloc mem
+        * in intel Proximity module and can only
+        * be used in intel Proximity mode
+        */
+       struct proxim proximity;
+
+       /*for bt coexist use*/
+       struct bt_coexist_info btcoexist;
+
+       /* separate 92ee from other ICs,
+        * 92ee use new trx flow.
+        */
+       bool use_new_trx_flow;
+
        /*This must be the last item so
           that it points to the data allocated
           beyond  this structure like:
@@ -2079,6 +2440,15 @@ enum bt_co_type {
        BT_CSR_BC8 = 4,
        BT_RTL8756 = 5,
        BT_RTL8723A = 6,
+       BT_RTL8821A = 7,
+       BT_RTL8723B = 8,
+       BT_RTL8192E = 9,
+       BT_RTL8812A = 11,
+};
+
+enum bt_total_ant_num {
+       ANT_TOTAL_X2 = 0,
+       ANT_TOTAL_X1 = 1
 };
 
 enum bt_cur_state {
@@ -2104,62 +2474,6 @@ enum bt_radio_shared {
        BT_RADIO_INDIVIDUAL = 1,
 };
 
-struct bt_coexist_info {
-
-       /* EEPROM BT info. */
-       u8 eeprom_bt_coexist;
-       u8 eeprom_bt_type;
-       u8 eeprom_bt_ant_num;
-       u8 eeprom_bt_ant_isol;
-       u8 eeprom_bt_radio_shared;
-
-       u8 bt_coexistence;
-       u8 bt_ant_num;
-       u8 bt_coexist_type;
-       u8 bt_state;
-       u8 bt_cur_state;        /* 0:on, 1:off */
-       u8 bt_ant_isolation;    /* 0:good, 1:bad */
-       u8 bt_pape_ctrl;        /* 0:SW, 1:SW/HW dynamic */
-       u8 bt_service;
-       u8 bt_radio_shared_type;
-       u8 bt_rfreg_origin_1e;
-       u8 bt_rfreg_origin_1f;
-       u8 bt_rssi_state;
-       u32 ratio_tx;
-       u32 ratio_pri;
-       u32 bt_edca_ul;
-       u32 bt_edca_dl;
-
-       bool init_set;
-       bool bt_busy_traffic;
-       bool bt_traffic_mode_set;
-       bool bt_non_traffic_mode_set;
-
-       bool fw_coexist_all_off;
-       bool sw_coexist_all_off;
-       bool hw_coexist_all_off;
-       u32 cstate;
-       u32 previous_state;
-       u32 cstate_h;
-       u32 previous_state_h;
-
-       u8 bt_pre_rssi_state;
-       u8 bt_pre_rssi_state1;
-
-       u8 reg_bt_iso;
-       u8 reg_bt_sco;
-       bool balance_on;
-       u8 bt_active_zero_cnt;
-       bool cur_bt_disabled;
-       bool pre_bt_disabled;
-
-       u8 bt_profile_case;
-       u8 bt_profile_action;
-       bool bt_busy;
-       bool hold_for_bt_operation;
-       u8 lps_counter;
-};
-
 
 /****************************************
        mem access macro define start
index 998e95895f9dc8beed8cd3d7c3b06f1e72259b90..a92bd3e89796b181902bc387f49ff8eafaf31d04 100644 (file)
 #include <linux/err.h>
 #include <linux/wl12xx.h>
 
-static struct wl12xx_platform_data *platform_data;
+static struct wl12xx_platform_data *wl12xx_platform_data;
 
 int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
 {
-       if (platform_data)
+       if (wl12xx_platform_data)
                return -EBUSY;
        if (!data)
                return -EINVAL;
 
-       platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
-       if (!platform_data)
+       wl12xx_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
+       if (!wl12xx_platform_data)
                return -ENOMEM;
 
        return 0;
@@ -41,9 +41,34 @@ int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
 
 struct wl12xx_platform_data *wl12xx_get_platform_data(void)
 {
-       if (!platform_data)
+       if (!wl12xx_platform_data)
                return ERR_PTR(-ENODEV);
 
-       return platform_data;
+       return wl12xx_platform_data;
 }
 EXPORT_SYMBOL(wl12xx_get_platform_data);
+
+static struct wl1251_platform_data *wl1251_platform_data;
+
+int __init wl1251_set_platform_data(const struct wl1251_platform_data *data)
+{
+       if (wl1251_platform_data)
+               return -EBUSY;
+       if (!data)
+               return -EINVAL;
+
+       wl1251_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
+       if (!wl1251_platform_data)
+               return -ENOMEM;
+
+       return 0;
+}
+
+struct wl1251_platform_data *wl1251_get_platform_data(void)
+{
+       if (!wl1251_platform_data)
+               return ERR_PTR(-ENODEV);
+
+       return wl1251_platform_data;
+}
+EXPORT_SYMBOL(wl1251_get_platform_data);
index 223649bcaa5a6764cff615bd9f1716b16810cc00..bf1fa18b9786253159d634ec1f846f70d8551bc8 100644 (file)
@@ -448,7 +448,7 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
         * 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.scan_options |= cpu_to_le16(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 123c4bb50e0a0c2eff220c4509c2ece5aab7b365..cde0eaf99714b4054176bd7a3cad9e850d97abea 100644 (file)
@@ -180,7 +180,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
        wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
 
        /* The actual length doesn't include the target's alignment */
-       skb->len = desc->length  - PLCP_HEADER_LENGTH;
+       skb_trim(skb, desc->length - PLCP_HEADER_LENGTH);
 
        fc = (u16 *)skb->data;
 
index e2b3d9c541e830f23fdc3703a6ddc5d48c276de0..b661f896e9fe148ff322879c541c67c755a9a1a4 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/wl12xx.h>
 #include <linux/irq.h>
 #include <linux/pm_runtime.h>
+#include <linux/gpio.h>
 
 #include "wl1251.h"
 
@@ -182,8 +183,9 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
                 * callback in case it wants to do any additional setup,
                 * for example enabling clock buffer for the module.
                 */
-               if (wl->set_power)
-                       wl->set_power(true);
+               if (gpio_is_valid(wl->power_gpio))
+                       gpio_set_value(wl->power_gpio, true);
+
 
                ret = pm_runtime_get_sync(&func->dev);
                if (ret < 0) {
@@ -203,8 +205,8 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
                if (ret < 0)
                        goto out;
 
-               if (wl->set_power)
-                       wl->set_power(false);
+               if (gpio_is_valid(wl->power_gpio))
+                       gpio_set_value(wl->power_gpio, false);
        }
 
 out:
@@ -227,7 +229,7 @@ static int wl1251_sdio_probe(struct sdio_func *func,
        struct wl1251 *wl;
        struct ieee80211_hw *hw;
        struct wl1251_sdio *wl_sdio;
-       const struct wl12xx_platform_data *wl12xx_board_data;
+       const struct wl1251_platform_data *wl1251_board_data;
 
        hw = wl1251_alloc_hw();
        if (IS_ERR(hw))
@@ -254,11 +256,20 @@ static int wl1251_sdio_probe(struct sdio_func *func,
        wl->if_priv = wl_sdio;
        wl->if_ops = &wl1251_sdio_ops;
 
-       wl12xx_board_data = wl12xx_get_platform_data();
-       if (!IS_ERR(wl12xx_board_data)) {
-               wl->set_power = wl12xx_board_data->set_power;
-               wl->irq = wl12xx_board_data->irq;
-               wl->use_eeprom = wl12xx_board_data->use_eeprom;
+       wl1251_board_data = wl1251_get_platform_data();
+       if (!IS_ERR(wl1251_board_data)) {
+               wl->power_gpio = wl1251_board_data->power_gpio;
+               wl->irq = wl1251_board_data->irq;
+               wl->use_eeprom = wl1251_board_data->use_eeprom;
+       }
+
+       if (gpio_is_valid(wl->power_gpio)) {
+               ret = devm_gpio_request(&func->dev, wl->power_gpio,
+                                                               "wl1251 power");
+               if (ret) {
+                       wl1251_error("Failed to request gpio: %d\n", ret);
+                       goto disable;
+               }
        }
 
        if (wl->irq) {
index 1342f81e683d1498bb16d5904d032009244bed58..b06d36d99362703c1b7aa35e6aadd5cab29e0d8f 100644 (file)
 #include <linux/crc7.h>
 #include <linux/spi/spi.h>
 #include <linux/wl12xx.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
 
 #include "wl1251.h"
 #include "reg.h"
@@ -221,8 +225,8 @@ static void wl1251_spi_disable_irq(struct wl1251 *wl)
 
 static int wl1251_spi_set_power(struct wl1251 *wl, bool enable)
 {
-       if (wl->set_power)
-               wl->set_power(enable);
+       if (gpio_is_valid(wl->power_gpio))
+               gpio_set_value(wl->power_gpio, enable);
 
        return 0;
 }
@@ -238,13 +242,13 @@ static const struct wl1251_if_operations wl1251_spi_ops = {
 
 static int wl1251_spi_probe(struct spi_device *spi)
 {
-       struct wl12xx_platform_data *pdata;
+       struct wl1251_platform_data *pdata = dev_get_platdata(&spi->dev);
+       struct device_node *np = spi->dev.of_node;
        struct ieee80211_hw *hw;
        struct wl1251 *wl;
        int ret;
 
-       pdata = dev_get_platdata(&spi->dev);
-       if (!pdata) {
+       if (!np && !pdata) {
                wl1251_error("no platform data");
                return -ENODEV;
        }
@@ -271,22 +275,42 @@ static int wl1251_spi_probe(struct spi_device *spi)
                goto out_free;
        }
 
-       wl->set_power = pdata->set_power;
-       if (!wl->set_power) {
-               wl1251_error("set power function missing in platform data");
-               return -ENODEV;
+       if (np) {
+               wl->use_eeprom = of_property_read_bool(np, "ti,wl1251-has-eeprom");
+               wl->power_gpio = of_get_named_gpio(np, "ti,power-gpio", 0);
+       } else if (pdata) {
+               wl->power_gpio = pdata->power_gpio;
+               wl->use_eeprom = pdata->use_eeprom;
+       }
+
+       if (wl->power_gpio == -EPROBE_DEFER) {
+               ret = -EPROBE_DEFER;
+               goto out_free;
+       }
+
+       if (gpio_is_valid(wl->power_gpio)) {
+               ret = devm_gpio_request_one(&spi->dev, wl->power_gpio,
+                                       GPIOF_OUT_INIT_LOW, "wl1251 power");
+               if (ret) {
+                       wl1251_error("Failed to request gpio: %d\n", ret);
+                       goto out_free;
+               }
+       } else {
+               wl1251_error("set power gpio missing in platform data");
+               ret = -ENODEV;
+               goto out_free;
        }
 
        wl->irq = spi->irq;
        if (wl->irq < 0) {
                wl1251_error("irq missing in platform data");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto out_free;
        }
 
-       wl->use_eeprom = pdata->use_eeprom;
-
        irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
-       ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
+       ret = devm_request_irq(&spi->dev, wl->irq, wl1251_irq, 0,
+                                                       DRIVER_NAME, wl);
        if (ret < 0) {
                wl1251_error("request_irq() failed: %d", ret);
                goto out_free;
@@ -294,16 +318,26 @@ static int wl1251_spi_probe(struct spi_device *spi)
 
        irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
 
+       wl->vio = devm_regulator_get(&spi->dev, "vio");
+       if (IS_ERR(wl->vio)) {
+               ret = PTR_ERR(wl->vio);
+               wl1251_error("vio regulator missing: %d", ret);
+               goto out_free;
+       }
+
+       ret = regulator_enable(wl->vio);
+       if (ret)
+               goto out_free;
+
        ret = wl1251_init_ieee80211(wl);
        if (ret)
-               goto out_irq;
+               goto disable_regulator;
 
        return 0;
 
- out_irq:
-       free_irq(wl->irq, wl);
-
- out_free:
+disable_regulator:
+       regulator_disable(wl->vio);
+out_free:
        ieee80211_free_hw(hw);
 
        return ret;
@@ -315,6 +349,7 @@ static int wl1251_spi_remove(struct spi_device *spi)
 
        free_irq(wl->irq, wl);
        wl1251_free_hw(wl);
+       regulator_disable(wl->vio);
 
        return 0;
 }
index 235617a7716d59ff4a699427540c1ecb4a612178..16dae5269175ec7d531e516a9077f1e112a95d57 100644 (file)
@@ -276,10 +276,12 @@ struct wl1251 {
        void *if_priv;
        const struct wl1251_if_operations *if_ops;
 
-       void (*set_power)(bool enable);
+       int power_gpio;
        int irq;
        bool use_eeprom;
 
+       struct regulator *vio;
+
        spinlock_t wl_lock;
 
        enum wl1251_state state;
index 7aae5b3a0c2ca72ad195af5928e31c94011feedf..ed88d39134839e34510d83252949dbbb2a964e83 100644 (file)
@@ -800,7 +800,7 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
        size_t len;
 
        /* Make sure we have enough room */
-       len = min(maxlen, (size_t)(PAGE_SIZE - wl->fwlog_size));
+       len = min_t(size_t, maxlen, PAGE_SIZE - wl->fwlog_size);
 
        /* Fill the FW log file, consumed by the sysfs fwlog entry */
        memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
@@ -3668,8 +3668,8 @@ out:
        return ret;
 }
 
-static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
-                                     struct ieee80211_vif *vif)
+static int wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif)
 {
        struct wl1271 *wl = hw->priv;
        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
@@ -3691,6 +3691,8 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
        wl1271_ps_elp_sleep(wl);
 out:
        mutex_unlock(&wl->mutex);
+
+       return 0;
 }
 
 static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
index b2c018dccf1887bb8dbdd5b85d9a88e0d30ff46e..dbe826dd7c23c49a38a08988cb24c50764d3efaa 100644 (file)
@@ -211,7 +211,7 @@ static int __must_check wl12xx_spi_raw_read(struct device *child, int addr,
        u32 chunk_len;
 
        while (len > 0) {
-               chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
+               chunk_len = min_t(size_t, WSPI_MAX_CHUNK_SIZE, len);
 
                cmd = &wl->buffer_cmd;
                busy_buf = wl->buffer_busyword;
@@ -285,7 +285,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
        cmd = &commands[0];
        i = 0;
        while (len > 0) {
-               chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
+               chunk_len = min_t(size_t, WSPI_MAX_CHUNK_SIZE, len);
 
                *cmd = 0;
                *cmd |= WSPI_CMD_WRITE;
index 8e583497940d0b0d728ee2151d1cfa0f04def249..24dd288d68098f2e87b12b546c6fe38460501edc 100644 (file)
@@ -152,7 +152,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
        }
 
        /* Seeking is not supported - old logs are not kept. Disregard pos. */
-       len = min(count, (size_t)wl->fwlog_size);
+       len = min_t(size_t, count, wl->fwlog_size);
        wl->fwlog_size -= len;
        memcpy(buffer, wl->fwlog, len);
 
index d24d4a958c6731a44fe10d9c83ee32567c3fe7ed..d5c371d77ddf238d00e6ce7c3e46e2c6a4a6136b 100644 (file)
@@ -42,8 +42,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <linux/etherdevice.h>
+#include <net/cfg80211.h>
 
 #include <net/iw_handler.h>
 
@@ -1454,7 +1453,8 @@ static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info,
 {
        struct wl3501_card *this = netdev_priv(dev);
 
-       wrqu->freq.m = ieee80211_dsss_chan_to_freq(this->chan) * 100000;
+       wrqu->freq.m = 100000 *
+               ieee80211_channel_to_frequency(this->chan, IEEE80211_BAND_2GHZ);
        wrqu->freq.e = 1;
        return 0;
 }
index d39c4178c33a61b3291958904c74f03a754f47a3..6f5c793a7855e90f7255633e15baa0608676c957 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
-#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
 #include <net/iw_handler.h>
 #include <linux/string.h>
 #include <linux/if_arp.h>
@@ -914,11 +914,8 @@ static int zd1201_set_freq(struct net_device *dev,
 
        if (freq->e == 0)
                channel = freq->m;
-       else {
-               channel = ieee80211_freq_to_dsss_chan(freq->m);
-               if (channel < 0)
-                       channel = 0;
-       }
+       else
+               channel = ieee80211_frequency_to_channel(freq->m);
 
        err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel);
        if (err)
index ae413a2cbee71402b5cc3732940d262237d6c792..bef37be402b869fde5012da20aed30017bbcac81 100644 (file)
 typedef unsigned int pending_ring_idx_t;
 #define INVALID_PENDING_RING_IDX (~0U)
 
-/* For the head field in pending_tx_info: it is used to indicate
- * whether this tx info is the head of one or more coalesced requests.
- *
- * When head != INVALID_PENDING_RING_IDX, it means the start of a new
- * tx requests queue and the end of previous queue.
- *
- * An example sequence of head fields (I = INVALID_PENDING_RING_IDX):
- *
- * ...|0 I I I|5 I|9 I I I|...
- * -->|<-INUSE----------------
- *
- * After consuming the first slot(s) we have:
- *
- * ...|V V V V|5 I|9 I I I|...
- * -----FREE->|<-INUSE--------
- *
- * where V stands for "valid pending ring index". Any number other
- * than INVALID_PENDING_RING_IDX is OK. These entries are considered
- * free and can contain any number other than
- * INVALID_PENDING_RING_IDX. In practice we use 0.
- *
- * The in use non-INVALID_PENDING_RING_IDX (say 0, 5 and 9 in the
- * above example) number is the index into pending_tx_info and
- * mmap_pages arrays.
- */
 struct pending_tx_info {
-       struct xen_netif_tx_request req; /* coalesced tx request */
-       pending_ring_idx_t head; /* head != INVALID_PENDING_RING_IDX
-                                 * if it is head of one or more tx
-                                 * reqs
-                                 */
+       struct xen_netif_tx_request req; /* tx request */
+       /* Callback data for released SKBs. The callback is always
+        * xenvif_zerocopy_callback, desc contains the pending_idx, which is
+        * also an index in pending_tx_info array. It is initialized in
+        * xenvif_alloc and it never changes.
+        * skb_shinfo(skb)->destructor_arg points to the first mapped slot's
+        * callback_struct in this array of struct pending_tx_info's, then ctx
+        * to the next, or NULL if there is no more slot for this skb.
+        * ubuf_to_vif is a helper which finds the struct xenvif from a pointer
+        * to this field.
+        */
+       struct ubuf_info callback_struct;
 };
 
 #define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
@@ -108,6 +90,15 @@ struct xenvif_rx_meta {
  */
 #define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE)
 
+#define NETBACK_INVALID_HANDLE -1
+
+/* To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating
+ * the maximum slots a valid packet can use. Now this value is defined
+ * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by
+ * all backend.
+ */
+#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN
+
 struct xenvif {
        /* Unique identifier for this interface. */
        domid_t          domid;
@@ -126,13 +117,28 @@ struct xenvif {
        pending_ring_idx_t pending_cons;
        u16 pending_ring[MAX_PENDING_REQS];
        struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
-
-       /* Coalescing tx requests before copying makes number of grant
-        * copy ops greater or equal to number of slots required. In
-        * worst case a tx request consumes 2 gnttab_copy.
+       grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
+
+       struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
+       struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
+       /* passed to gnttab_[un]map_refs with pages under (un)mapping */
+       struct page *pages_to_map[MAX_PENDING_REQS];
+       struct page *pages_to_unmap[MAX_PENDING_REQS];
+
+       /* This prevents zerocopy callbacks  to race over dealloc_ring */
+       spinlock_t callback_lock;
+       /* This prevents dealloc thread and NAPI instance to race over response
+        * creation and pending_ring in xenvif_idx_release. In xenvif_tx_err
+        * it only protect response creation
         */
-       struct gnttab_copy tx_copy_ops[2*MAX_PENDING_REQS];
-
+       spinlock_t response_lock;
+       pending_ring_idx_t dealloc_prod;
+       pending_ring_idx_t dealloc_cons;
+       u16 dealloc_ring[MAX_PENDING_REQS];
+       struct task_struct *dealloc_task;
+       wait_queue_head_t dealloc_wq;
+       struct timer_list dealloc_delay;
+       bool dealloc_delay_timed_out;
 
        /* Use kthread for guest RX */
        struct task_struct *task;
@@ -144,6 +150,9 @@ struct xenvif {
        struct xen_netif_rx_back_ring rx;
        struct sk_buff_head rx_queue;
        RING_IDX rx_last_skb_slots;
+       bool rx_queue_purge;
+
+       struct timer_list wake_queue;
 
        /* This array is allocated seperately as it is large */
        struct gnttab_copy *grant_copy_op;
@@ -175,6 +184,10 @@ struct xenvif {
 
        /* Statistics */
        unsigned long rx_gso_checksum_fixup;
+       unsigned long tx_zerocopy_sent;
+       unsigned long tx_zerocopy_success;
+       unsigned long tx_zerocopy_fail;
+       unsigned long tx_frag_overflow;
 
        /* Miscellaneous private stuff. */
        struct net_device *dev;
@@ -216,9 +229,11 @@ void xenvif_carrier_off(struct xenvif *vif);
 
 int xenvif_tx_action(struct xenvif *vif, int budget);
 
-int xenvif_kthread(void *data);
+int xenvif_kthread_guest_rx(void *data);
 void xenvif_kick_thread(struct xenvif *vif);
 
+int xenvif_dealloc_kthread(void *data);
+
 /* Determine whether the needed number of slots (req) are available,
  * and set req_event if not.
  */
@@ -226,6 +241,30 @@ bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed);
 
 void xenvif_stop_queue(struct xenvif *vif);
 
+/* Callback from stack when TX packet can be released */
+void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success);
+
+/* Unmap a pending page and release it back to the guest */
+void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx);
+
+static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif)
+{
+       return MAX_PENDING_REQS -
+               vif->pending_prod + vif->pending_cons;
+}
+
+static inline bool xenvif_tx_pending_slots_available(struct xenvif *vif)
+{
+       return nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX
+               < MAX_PENDING_REQS;
+}
+
+/* Callback from stack when TX packet can be released */
+void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success);
+
 extern bool separate_tx_rx_irq;
 
+extern unsigned int rx_drain_timeout_msecs;
+extern unsigned int rx_drain_timeout_jiffies;
+
 #endif /* __XEN_NETBACK__COMMON_H__ */
index 7669d49a67e2271bebe14e80aaaa9c59312edea2..a6a8c1579eb97987a2bf8fea91fc646403817d9e 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <xen/events.h>
 #include <asm/xen/hypercall.h>
+#include <xen/balloon.h>
 
 #define XENVIF_QUEUE_LENGTH 32
 #define XENVIF_NAPI_WEIGHT  64
@@ -87,7 +88,8 @@ static int xenvif_poll(struct napi_struct *napi, int budget)
                local_irq_save(flags);
 
                RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
-               if (!more_to_do)
+               if (!(more_to_do &&
+                     xenvif_tx_pending_slots_available(vif)))
                        __napi_complete(napi);
 
                local_irq_restore(flags);
@@ -113,6 +115,18 @@ static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static void xenvif_wake_queue(unsigned long data)
+{
+       struct xenvif *vif = (struct xenvif *)data;
+
+       if (netif_queue_stopped(vif->dev)) {
+               netdev_err(vif->dev, "draining TX queue\n");
+               vif->rx_queue_purge = true;
+               xenvif_kick_thread(vif);
+               netif_wake_queue(vif->dev);
+       }
+}
+
 static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct xenvif *vif = netdev_priv(dev);
@@ -121,7 +135,9 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
        BUG_ON(skb->dev != dev);
 
        /* Drop the packet if vif is not ready */
-       if (vif->task == NULL || !xenvif_schedulable(vif))
+       if (vif->task == NULL ||
+           vif->dealloc_task == NULL ||
+           !xenvif_schedulable(vif))
                goto drop;
 
        /* At best we'll need one slot for the header and one for each
@@ -132,16 +148,20 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* If the skb is GSO then we'll also need an extra slot for the
         * metadata.
         */
-       if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
-           skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+       if (skb_is_gso(skb))
                min_slots_needed++;
 
        /* If the skb can't possibly fit in the remaining slots
         * then turn off the queue to give the ring a chance to
         * drain.
         */
-       if (!xenvif_rx_ring_slots_available(vif, min_slots_needed))
+       if (!xenvif_rx_ring_slots_available(vif, min_slots_needed)) {
+               vif->wake_queue.function = xenvif_wake_queue;
+               vif->wake_queue.data = (unsigned long)vif;
                xenvif_stop_queue(vif);
+               mod_timer(&vif->wake_queue,
+                       jiffies + rx_drain_timeout_jiffies);
+       }
 
        skb_queue_tail(&vif->rx_queue, skb);
        xenvif_kick_thread(vif);
@@ -234,6 +254,28 @@ static const struct xenvif_stat {
                "rx_gso_checksum_fixup",
                offsetof(struct xenvif, rx_gso_checksum_fixup)
        },
+       /* If (sent != success + fail), there are probably packets never
+        * freed up properly!
+        */
+       {
+               "tx_zerocopy_sent",
+               offsetof(struct xenvif, tx_zerocopy_sent),
+       },
+       {
+               "tx_zerocopy_success",
+               offsetof(struct xenvif, tx_zerocopy_success),
+       },
+       {
+               "tx_zerocopy_fail",
+               offsetof(struct xenvif, tx_zerocopy_fail)
+       },
+       /* Number of packets exceeding MAX_SKB_FRAG slots. You should use
+        * a guest with the same MAX_SKB_FRAG
+        */
+       {
+               "tx_frag_overflow",
+               offsetof(struct xenvif, tx_frag_overflow)
+       },
 };
 
 static int xenvif_get_sset_count(struct net_device *dev, int string_set)
@@ -327,6 +369,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
        init_timer(&vif->credit_timeout);
        vif->credit_window_start = get_jiffies_64();
 
+       init_timer(&vif->wake_queue);
+
        dev->netdev_ops = &xenvif_netdev_ops;
        dev->hw_features = NETIF_F_SG |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
@@ -343,8 +387,27 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
        vif->pending_prod = MAX_PENDING_REQS;
        for (i = 0; i < MAX_PENDING_REQS; i++)
                vif->pending_ring[i] = i;
-       for (i = 0; i < MAX_PENDING_REQS; i++)
-               vif->mmap_pages[i] = NULL;
+       spin_lock_init(&vif->callback_lock);
+       spin_lock_init(&vif->response_lock);
+       /* If ballooning is disabled, this will consume real memory, so you
+        * better enable it. The long term solution would be to use just a
+        * bunch of valid page descriptors, without dependency on ballooning
+        */
+       err = alloc_xenballooned_pages(MAX_PENDING_REQS,
+                                      vif->mmap_pages,
+                                      false);
+       if (err) {
+               netdev_err(dev, "Could not reserve mmap_pages\n");
+               return ERR_PTR(-ENOMEM);
+       }
+       for (i = 0; i < MAX_PENDING_REQS; i++) {
+               vif->pending_tx_info[i].callback_struct = (struct ubuf_info)
+                       { .callback = xenvif_zerocopy_callback,
+                         .ctx = NULL,
+                         .desc = i };
+               vif->grant_tx_handle[i] = NETBACK_INVALID_HANDLE;
+       }
+       init_timer(&vif->dealloc_delay);
 
        /*
         * Initialise a dummy MAC address. We choose the numerically
@@ -382,12 +445,14 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
 
        BUG_ON(vif->tx_irq);
        BUG_ON(vif->task);
+       BUG_ON(vif->dealloc_task);
 
        err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
        if (err < 0)
                goto err;
 
        init_waitqueue_head(&vif->wq);
+       init_waitqueue_head(&vif->dealloc_wq);
 
        if (tx_evtchn == rx_evtchn) {
                /* feature-split-event-channels == 0 */
@@ -421,8 +486,8 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
                disable_irq(vif->rx_irq);
        }
 
-       task = kthread_create(xenvif_kthread,
-                             (void *)vif, "%s", vif->dev->name);
+       task = kthread_create(xenvif_kthread_guest_rx,
+                             (void *)vif, "%s-guest-rx", vif->dev->name);
        if (IS_ERR(task)) {
                pr_warn("Could not allocate kthread for %s\n", vif->dev->name);
                err = PTR_ERR(task);
@@ -431,6 +496,16 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
 
        vif->task = task;
 
+       task = kthread_create(xenvif_dealloc_kthread,
+                             (void *)vif, "%s-dealloc", vif->dev->name);
+       if (IS_ERR(task)) {
+               pr_warn("Could not allocate kthread for %s\n", vif->dev->name);
+               err = PTR_ERR(task);
+               goto err_rx_unbind;
+       }
+
+       vif->dealloc_task = task;
+
        rtnl_lock();
        if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
                dev_set_mtu(vif->dev, ETH_DATA_LEN);
@@ -441,6 +516,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
        rtnl_unlock();
 
        wake_up_process(vif->task);
+       wake_up_process(vif->dealloc_task);
 
        return 0;
 
@@ -474,10 +550,17 @@ void xenvif_disconnect(struct xenvif *vif)
                xenvif_carrier_off(vif);
 
        if (vif->task) {
+               del_timer_sync(&vif->wake_queue);
                kthread_stop(vif->task);
                vif->task = NULL;
        }
 
+       if (vif->dealloc_task) {
+               del_timer_sync(&vif->dealloc_delay);
+               kthread_stop(vif->dealloc_task);
+               vif->dealloc_task = NULL;
+       }
+
        if (vif->tx_irq) {
                if (vif->tx_irq == vif->rx_irq)
                        unbind_from_irqhandler(vif->tx_irq, vif);
@@ -493,6 +576,36 @@ void xenvif_disconnect(struct xenvif *vif)
 
 void xenvif_free(struct xenvif *vif)
 {
+       int i, unmap_timeout = 0;
+       /* Here we want to avoid timeout messages if an skb can be legitimatly
+        * stucked somewhere else. Realisticly this could be an another vif's
+        * internal or QDisc queue. That another vif also has this
+        * rx_drain_timeout_msecs timeout, but the timer only ditches the
+        * internal queue. After that, the QDisc queue can put in worst case
+        * XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS skbs into that another vif's
+        * internal queue, so we need several rounds of such timeouts until we
+        * can be sure that no another vif should have skb's from us. We are
+        * not sending more skb's, so newly stucked packets are not interesting
+        * for us here.
+        */
+       unsigned int worst_case_skb_lifetime = (rx_drain_timeout_msecs/1000) *
+               DIV_ROUND_UP(XENVIF_QUEUE_LENGTH, (XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS));
+
+       for (i = 0; i < MAX_PENDING_REQS; ++i) {
+               if (vif->grant_tx_handle[i] != NETBACK_INVALID_HANDLE) {
+                       unmap_timeout++;
+                       schedule_timeout(msecs_to_jiffies(1000));
+                       if (unmap_timeout > worst_case_skb_lifetime &&
+                           net_ratelimit())
+                               netdev_err(vif->dev,
+                                          "Page still granted! Index: %x\n",
+                                          i);
+                       i = -1;
+               }
+       }
+
+       free_xenballooned_pages(MAX_PENDING_REQS, vif->mmap_pages);
+
        netif_napi_del(&vif->napi);
 
        unregister_netdev(vif->dev);
index e5284bca2d90e6e80ec0d682475404e9dc236e33..5a8c4a43c5227b4abd549c080530f0075b85ed3c 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/kthread.h>
 #include <linux/if_vlan.h>
 #include <linux/udp.h>
+#include <linux/highmem.h>
 
 #include <net/tcp.h>
 
 bool separate_tx_rx_irq = 1;
 module_param(separate_tx_rx_irq, bool, 0644);
 
+/* When guest ring is filled up, qdisc queues the packets for us, but we have
+ * to timeout them, otherwise other guests' packets can get stucked there
+ */
+unsigned int rx_drain_timeout_msecs = 10000;
+module_param(rx_drain_timeout_msecs, uint, 0444);
+unsigned int rx_drain_timeout_jiffies;
+
 /*
  * This is the maximum slots a skb can have. If a guest sends a skb
  * which exceeds this limit it is considered malicious.
@@ -62,24 +70,6 @@ module_param(separate_tx_rx_irq, bool, 0644);
 static unsigned int fatal_skb_slots = FATAL_SKB_SLOTS_DEFAULT;
 module_param(fatal_skb_slots, uint, 0444);
 
-/*
- * To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating
- * the maximum slots a valid packet can use. Now this value is defined
- * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by
- * all backend.
- */
-#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN
-
-/*
- * If head != INVALID_PENDING_RING_IDX, it means this tx request is head of
- * one or more merged tx requests, otherwise it is the continuation of
- * previous tx request.
- */
-static inline int pending_tx_is_head(struct xenvif *vif, RING_IDX idx)
-{
-       return vif->pending_tx_info[idx].head != INVALID_PENDING_RING_IDX;
-}
-
 static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx,
                               u8 status);
 
@@ -109,6 +99,18 @@ static inline unsigned long idx_to_kaddr(struct xenvif *vif,
        return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx));
 }
 
+/* Find the containing VIF's structure from a pointer in pending_tx_info array
+ */
+static inline struct xenvif* ubuf_to_vif(struct ubuf_info *ubuf)
+{
+       u16 pending_idx = ubuf->desc;
+       struct pending_tx_info *temp =
+               container_of(ubuf, struct pending_tx_info, callback_struct);
+       return container_of(temp - pending_idx,
+                           struct xenvif,
+                           pending_tx_info[0]);
+}
+
 /* This is a miniumum size for the linear area to avoid lots of
  * calls to __pskb_pull_tail() as we set up checksum offsets. The
  * value 128 was chosen as it covers all IPv4 and most likely
@@ -131,10 +133,9 @@ static inline pending_ring_idx_t pending_index(unsigned i)
        return i & (MAX_PENDING_REQS-1);
 }
 
-static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif)
+static inline pending_ring_idx_t nr_free_slots(struct xen_netif_tx_back_ring *ring)
 {
-       return MAX_PENDING_REQS -
-               vif->pending_prod + vif->pending_cons;
+       return ring->nr_ents -  (ring->sring->req_prod - ring->rsp_prod_pvt);
 }
 
 bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed)
@@ -235,12 +236,14 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif *vif,
 static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
                                 struct netrx_pending_operations *npo,
                                 struct page *page, unsigned long size,
-                                unsigned long offset, int *head)
+                                unsigned long offset, int *head,
+                                struct xenvif *foreign_vif,
+                                grant_ref_t foreign_gref)
 {
        struct gnttab_copy *copy_gop;
        struct xenvif_rx_meta *meta;
        unsigned long bytes;
-       int gso_type;
+       int gso_type = XEN_NETIF_GSO_TYPE_NONE;
 
        /* Data must not cross a page boundary. */
        BUG_ON(size + offset > PAGE_SIZE<<compound_order(page));
@@ -277,8 +280,15 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
                copy_gop->flags = GNTCOPY_dest_gref;
                copy_gop->len = bytes;
 
-               copy_gop->source.domid = DOMID_SELF;
-               copy_gop->source.u.gmfn = virt_to_mfn(page_address(page));
+               if (foreign_vif) {
+                       copy_gop->source.domid = foreign_vif->domid;
+                       copy_gop->source.u.ref = foreign_gref;
+                       copy_gop->flags |= GNTCOPY_source_gref;
+               } else {
+                       copy_gop->source.domid = DOMID_SELF;
+                       copy_gop->source.u.gmfn =
+                               virt_to_mfn(page_address(page));
+               }
                copy_gop->source.offset = offset;
 
                copy_gop->dest.domid = vif->domid;
@@ -299,12 +309,12 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
                }
 
                /* Leave a gap for the GSO descriptor. */
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
-                       gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
-               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
-                       gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
-               else
-                       gso_type = XEN_NETIF_GSO_TYPE_NONE;
+               if (skb_is_gso(skb)) {
+                       if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+                               gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+                       else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+                               gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
+               }
 
                if (*head && ((1 << gso_type) & vif->gso_mask))
                        vif->rx.req_cons++;
@@ -338,19 +348,18 @@ static int xenvif_gop_skb(struct sk_buff *skb,
        int head = 1;
        int old_meta_prod;
        int gso_type;
-       int gso_size;
+       struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg;
+       grant_ref_t foreign_grefs[MAX_SKB_FRAGS];
+       struct xenvif *foreign_vif = NULL;
 
        old_meta_prod = npo->meta_prod;
 
-       if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
-               gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
-               gso_size = skb_shinfo(skb)->gso_size;
-       } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
-               gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
-               gso_size = skb_shinfo(skb)->gso_size;
-       } else {
-               gso_type = XEN_NETIF_GSO_TYPE_NONE;
-               gso_size = 0;
+       gso_type = XEN_NETIF_GSO_TYPE_NONE;
+       if (skb_is_gso(skb)) {
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+                       gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+                       gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
        }
 
        /* Set up a GSO prefix descriptor, if necessary */
@@ -358,7 +367,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
                req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
                meta = npo->meta + npo->meta_prod++;
                meta->gso_type = gso_type;
-               meta->gso_size = gso_size;
+               meta->gso_size = skb_shinfo(skb)->gso_size;
                meta->size = 0;
                meta->id = req->id;
        }
@@ -368,7 +377,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
 
        if ((1 << gso_type) & vif->gso_mask) {
                meta->gso_type = gso_type;
-               meta->gso_size = gso_size;
+               meta->gso_size = skb_shinfo(skb)->gso_size;
        } else {
                meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
                meta->gso_size = 0;
@@ -379,6 +388,19 @@ static int xenvif_gop_skb(struct sk_buff *skb,
        npo->copy_off = 0;
        npo->copy_gref = req->gref;
 
+       if ((skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) &&
+                (ubuf->callback == &xenvif_zerocopy_callback)) {
+               int i = 0;
+               foreign_vif = ubuf_to_vif(ubuf);
+
+               do {
+                       u16 pending_idx = ubuf->desc;
+                       foreign_grefs[i++] =
+                               foreign_vif->pending_tx_info[pending_idx].req.gref;
+                       ubuf = (struct ubuf_info *) ubuf->ctx;
+               } while (ubuf);
+       }
+
        data = skb->data;
        while (data < skb_tail_pointer(skb)) {
                unsigned int offset = offset_in_page(data);
@@ -388,7 +410,9 @@ static int xenvif_gop_skb(struct sk_buff *skb,
                        len = skb_tail_pointer(skb) - data;
 
                xenvif_gop_frag_copy(vif, skb, npo,
-                                    virt_to_page(data), len, offset, &head);
+                                    virt_to_page(data), len, offset, &head,
+                                    NULL,
+                                    0);
                data += len;
        }
 
@@ -397,7 +421,9 @@ static int xenvif_gop_skb(struct sk_buff *skb,
                                     skb_frag_page(&skb_shinfo(skb)->frags[i]),
                                     skb_frag_size(&skb_shinfo(skb)->frags[i]),
                                     skb_shinfo(skb)->frags[i].page_offset,
-                                    &head);
+                                    &head,
+                                    foreign_vif,
+                                    foreign_grefs[i]);
        }
 
        return npo->meta_prod - old_meta_prod;
@@ -455,10 +481,12 @@ static void xenvif_add_frag_responses(struct xenvif *vif, int status,
        }
 }
 
-struct skb_cb_overlay {
+struct xenvif_rx_cb {
        int meta_slots_used;
 };
 
+#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb)
+
 void xenvif_kick_thread(struct xenvif *vif)
 {
        wake_up(&vif->wq);
@@ -474,7 +502,6 @@ static void xenvif_rx_action(struct xenvif *vif)
        LIST_HEAD(notify);
        int ret;
        unsigned long offset;
-       struct skb_cb_overlay *sco;
        bool need_to_notify = false;
 
        struct netrx_pending_operations npo = {
@@ -500,8 +527,9 @@ static void xenvif_rx_action(struct xenvif *vif)
                        size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
                        max_slots_needed += DIV_ROUND_UP(size, PAGE_SIZE);
                }
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
-                   skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+               if (skb_is_gso(skb) &&
+                  (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
+                   skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
                        max_slots_needed++;
 
                /* If the skb may not fit then bail out now */
@@ -513,9 +541,8 @@ static void xenvif_rx_action(struct xenvif *vif)
                } else
                        vif->rx_last_skb_slots = 0;
 
-               sco = (struct skb_cb_overlay *)skb->cb;
-               sco->meta_slots_used = xenvif_gop_skb(skb, &npo);
-               BUG_ON(sco->meta_slots_used > max_slots_needed);
+               XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo);
+               BUG_ON(XENVIF_RX_CB(skb)->meta_slots_used > max_slots_needed);
 
                __skb_queue_tail(&rxq, skb);
        }
@@ -529,7 +556,6 @@ static void xenvif_rx_action(struct xenvif *vif)
        gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod);
 
        while ((skb = __skb_dequeue(&rxq)) != NULL) {
-               sco = (struct skb_cb_overlay *)skb->cb;
 
                if ((1 << vif->meta[npo.meta_cons].gso_type) &
                    vif->gso_prefix_mask) {
@@ -540,19 +566,21 @@ static void xenvif_rx_action(struct xenvif *vif)
 
                        resp->offset = vif->meta[npo.meta_cons].gso_size;
                        resp->id = vif->meta[npo.meta_cons].id;
-                       resp->status = sco->meta_slots_used;
+                       resp->status = XENVIF_RX_CB(skb)->meta_slots_used;
 
                        npo.meta_cons++;
-                       sco->meta_slots_used--;
+                       XENVIF_RX_CB(skb)->meta_slots_used--;
                }
 
 
                vif->dev->stats.tx_bytes += skb->len;
                vif->dev->stats.tx_packets++;
 
-               status = xenvif_check_gop(vif, sco->meta_slots_used, &npo);
+               status = xenvif_check_gop(vif,
+                                         XENVIF_RX_CB(skb)->meta_slots_used,
+                                         &npo);
 
-               if (sco->meta_slots_used == 1)
+               if (XENVIF_RX_CB(skb)->meta_slots_used == 1)
                        flags = 0;
                else
                        flags = XEN_NETRXF_more_data;
@@ -589,13 +617,13 @@ static void xenvif_rx_action(struct xenvif *vif)
 
                xenvif_add_frag_responses(vif, status,
                                          vif->meta + npo.meta_cons + 1,
-                                         sco->meta_slots_used);
+                                         XENVIF_RX_CB(skb)->meta_slots_used);
 
                RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret);
 
                need_to_notify |= !!ret;
 
-               npo.meta_cons += sco->meta_slots_used;
+               npo.meta_cons += XENVIF_RX_CB(skb)->meta_slots_used;
                dev_kfree_skb(skb);
        }
 
@@ -645,9 +673,12 @@ static void xenvif_tx_err(struct xenvif *vif,
                          struct xen_netif_tx_request *txp, RING_IDX end)
 {
        RING_IDX cons = vif->tx.req_cons;
+       unsigned long flags;
 
        do {
+               spin_lock_irqsave(&vif->response_lock, flags);
                make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
+               spin_unlock_irqrestore(&vif->response_lock, flags);
                if (cons == end)
                        break;
                txp = RING_GET_REQUEST(&vif->tx, cons++);
@@ -759,180 +790,168 @@ static int xenvif_count_requests(struct xenvif *vif,
        return slots;
 }
 
-static struct page *xenvif_alloc_page(struct xenvif *vif,
-                                     u16 pending_idx)
+
+struct xenvif_tx_cb {
+       u16 pending_idx;
+};
+
+#define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
+
+static inline void xenvif_tx_create_gop(struct xenvif *vif,
+                                       u16 pending_idx,
+                                       struct xen_netif_tx_request *txp,
+                                       struct gnttab_map_grant_ref *gop)
 {
-       struct page *page;
+       vif->pages_to_map[gop-vif->tx_map_ops] = vif->mmap_pages[pending_idx];
+       gnttab_set_map_op(gop, idx_to_kaddr(vif, pending_idx),
+                         GNTMAP_host_map | GNTMAP_readonly,
+                         txp->gref, vif->domid);
+
+       memcpy(&vif->pending_tx_info[pending_idx].req, txp,
+              sizeof(*txp));
+}
 
-       page = alloc_page(GFP_ATOMIC|__GFP_COLD);
-       if (!page)
+static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
+{
+       struct sk_buff *skb =
+               alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN,
+                         GFP_ATOMIC | __GFP_NOWARN);
+       if (unlikely(skb == NULL))
                return NULL;
-       vif->mmap_pages[pending_idx] = page;
 
-       return page;
+       /* Packets passed to netif_rx() must have some headroom. */
+       skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+
+       /* Initialize it here to avoid later surprises */
+       skb_shinfo(skb)->destructor_arg = NULL;
+
+       return skb;
 }
 
-static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif,
-                                              struct sk_buff *skb,
-                                              struct xen_netif_tx_request *txp,
-                                              struct gnttab_copy *gop)
+static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif,
+                                                       struct sk_buff *skb,
+                                                       struct xen_netif_tx_request *txp,
+                                                       struct gnttab_map_grant_ref *gop)
 {
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        skb_frag_t *frags = shinfo->frags;
-       u16 pending_idx = *((u16 *)skb->data);
-       u16 head_idx = 0;
-       int slot, start;
-       struct page *page;
-       pending_ring_idx_t index, start_idx = 0;
-       uint16_t dst_offset;
-       unsigned int nr_slots;
-       struct pending_tx_info *first = NULL;
+       u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+       int start;
+       pending_ring_idx_t index;
+       unsigned int nr_slots, frag_overflow = 0;
 
        /* At this point shinfo->nr_frags is in fact the number of
         * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
         */
+       if (shinfo->nr_frags > MAX_SKB_FRAGS) {
+               frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS;
+               BUG_ON(frag_overflow > MAX_SKB_FRAGS);
+               shinfo->nr_frags = MAX_SKB_FRAGS;
+       }
        nr_slots = shinfo->nr_frags;
 
        /* Skip first skb fragment if it is on same page as header fragment. */
        start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
 
-       /* Coalesce tx requests, at this point the packet passed in
-        * should be <= 64K. Any packets larger than 64K have been
-        * handled in xenvif_count_requests().
-        */
-       for (shinfo->nr_frags = slot = start; slot < nr_slots;
-            shinfo->nr_frags++) {
-               struct pending_tx_info *pending_tx_info =
-                       vif->pending_tx_info;
+       for (shinfo->nr_frags = start; shinfo->nr_frags < nr_slots;
+            shinfo->nr_frags++, txp++, gop++) {
+               index = pending_index(vif->pending_cons++);
+               pending_idx = vif->pending_ring[index];
+               xenvif_tx_create_gop(vif, pending_idx, txp, gop);
+               frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx);
+       }
 
-               page = alloc_page(GFP_ATOMIC|__GFP_COLD);
-               if (!page)
-                       goto err;
-
-               dst_offset = 0;
-               first = NULL;
-               while (dst_offset < PAGE_SIZE && slot < nr_slots) {
-                       gop->flags = GNTCOPY_source_gref;
-
-                       gop->source.u.ref = txp->gref;
-                       gop->source.domid = vif->domid;
-                       gop->source.offset = txp->offset;
-
-                       gop->dest.domid = DOMID_SELF;
-
-                       gop->dest.offset = dst_offset;
-                       gop->dest.u.gmfn = virt_to_mfn(page_address(page));
-
-                       if (dst_offset + txp->size > PAGE_SIZE) {
-                               /* This page can only merge a portion
-                                * of tx request. Do not increment any
-                                * pointer / counter here. The txp
-                                * will be dealt with in future
-                                * rounds, eventually hitting the
-                                * `else` branch.
-                                */
-                               gop->len = PAGE_SIZE - dst_offset;
-                               txp->offset += gop->len;
-                               txp->size -= gop->len;
-                               dst_offset += gop->len; /* quit loop */
-                       } else {
-                               /* This tx request can be merged in the page */
-                               gop->len = txp->size;
-                               dst_offset += gop->len;
-
-                               index = pending_index(vif->pending_cons++);
-
-                               pending_idx = vif->pending_ring[index];
-
-                               memcpy(&pending_tx_info[pending_idx].req, txp,
-                                      sizeof(*txp));
-
-                               /* Poison these fields, corresponding
-                                * fields for head tx req will be set
-                                * to correct values after the loop.
-                                */
-                               vif->mmap_pages[pending_idx] = (void *)(~0UL);
-                               pending_tx_info[pending_idx].head =
-                                       INVALID_PENDING_RING_IDX;
-
-                               if (!first) {
-                                       first = &pending_tx_info[pending_idx];
-                                       start_idx = index;
-                                       head_idx = pending_idx;
-                               }
-
-                               txp++;
-                               slot++;
-                       }
+       if (frag_overflow) {
+               struct sk_buff *nskb = xenvif_alloc_skb(0);
+               if (unlikely(nskb == NULL)) {
+                       if (net_ratelimit())
+                               netdev_err(vif->dev,
+                                          "Can't allocate the frag_list skb.\n");
+                       return NULL;
+               }
+
+               shinfo = skb_shinfo(nskb);
+               frags = shinfo->frags;
 
-                       gop++;
+               for (shinfo->nr_frags = 0; shinfo->nr_frags < frag_overflow;
+                    shinfo->nr_frags++, txp++, gop++) {
+                       index = pending_index(vif->pending_cons++);
+                       pending_idx = vif->pending_ring[index];
+                       xenvif_tx_create_gop(vif, pending_idx, txp, gop);
+                       frag_set_pending_idx(&frags[shinfo->nr_frags],
+                                            pending_idx);
                }
 
-               first->req.offset = 0;
-               first->req.size = dst_offset;
-               first->head = start_idx;
-               vif->mmap_pages[head_idx] = page;
-               frag_set_pending_idx(&frags[shinfo->nr_frags], head_idx);
+               skb_shinfo(skb)->frag_list = nskb;
        }
 
-       BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS);
-
        return gop;
-err:
-       /* Unwind, freeing all pages and sending error responses. */
-       while (shinfo->nr_frags-- > start) {
-               xenvif_idx_release(vif,
-                               frag_get_pending_idx(&frags[shinfo->nr_frags]),
-                               XEN_NETIF_RSP_ERROR);
+}
+
+static inline void xenvif_grant_handle_set(struct xenvif *vif,
+                                          u16 pending_idx,
+                                          grant_handle_t handle)
+{
+       if (unlikely(vif->grant_tx_handle[pending_idx] !=
+                    NETBACK_INVALID_HANDLE)) {
+               netdev_err(vif->dev,
+                          "Trying to overwrite active handle! pending_idx: %x\n",
+                          pending_idx);
+               BUG();
        }
-       /* The head too, if necessary. */
-       if (start)
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
+       vif->grant_tx_handle[pending_idx] = handle;
+}
 
-       return NULL;
+static inline void xenvif_grant_handle_reset(struct xenvif *vif,
+                                            u16 pending_idx)
+{
+       if (unlikely(vif->grant_tx_handle[pending_idx] ==
+                    NETBACK_INVALID_HANDLE)) {
+               netdev_err(vif->dev,
+                          "Trying to unmap invalid handle! pending_idx: %x\n",
+                          pending_idx);
+               BUG();
+       }
+       vif->grant_tx_handle[pending_idx] = NETBACK_INVALID_HANDLE;
 }
 
 static int xenvif_tx_check_gop(struct xenvif *vif,
                               struct sk_buff *skb,
-                              struct gnttab_copy **gopp)
+                              struct gnttab_map_grant_ref **gopp)
 {
-       struct gnttab_copy *gop = *gopp;
-       u16 pending_idx = *((u16 *)skb->data);
+       struct gnttab_map_grant_ref *gop = *gopp;
+       u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        struct pending_tx_info *tx_info;
        int nr_frags = shinfo->nr_frags;
        int i, err, start;
-       u16 peek; /* peek into next tx request */
+       struct sk_buff *first_skb = NULL;
 
        /* Check status of header. */
        err = gop->status;
        if (unlikely(err))
                xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
+       else
+               xenvif_grant_handle_set(vif, pending_idx , gop->handle);
 
        /* Skip first skb fragment if it is on same page as header fragment. */
        start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
 
+check_frags:
        for (i = start; i < nr_frags; i++) {
                int j, newerr;
-               pending_ring_idx_t head;
 
                pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
                tx_info = &vif->pending_tx_info[pending_idx];
-               head = tx_info->head;
 
                /* Check error status: if okay then remember grant handle. */
-               do {
-                       newerr = (++gop)->status;
-                       if (newerr)
-                               break;
-                       peek = vif->pending_ring[pending_index(++head)];
-               } while (!pending_tx_is_head(vif, peek));
+               newerr = (++gop)->status;
 
                if (likely(!newerr)) {
+                       xenvif_grant_handle_set(vif, pending_idx , gop->handle);
                        /* Had a previous error? Invalidate this fragment. */
                        if (unlikely(err))
-                               xenvif_idx_release(vif, pending_idx,
-                                                  XEN_NETIF_RSP_OKAY);
+                               xenvif_idx_unmap(vif, pending_idx);
                        continue;
                }
 
@@ -942,20 +961,45 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
                /* Not the first error? Preceding frags already invalidated. */
                if (err)
                        continue;
-
                /* First error: invalidate header and preceding fragments. */
-               pending_idx = *((u16 *)skb->data);
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
+               if (!first_skb)
+                       pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+               else
+                       pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+               xenvif_idx_unmap(vif, pending_idx);
                for (j = start; j < i; j++) {
                        pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
-                       xenvif_idx_release(vif, pending_idx,
-                                          XEN_NETIF_RSP_OKAY);
+                       xenvif_idx_unmap(vif, pending_idx);
                }
 
                /* Remember the error: invalidate all subsequent fragments. */
                err = newerr;
        }
 
+       if (skb_has_frag_list(skb)) {
+               first_skb = skb;
+               skb = shinfo->frag_list;
+               shinfo = skb_shinfo(skb);
+               nr_frags = shinfo->nr_frags;
+               start = 0;
+
+               goto check_frags;
+       }
+
+       /* There was a mapping error in the frag_list skb. We have to unmap
+        * the first skb's frags
+        */
+       if (first_skb && err) {
+               int j;
+               shinfo = skb_shinfo(first_skb);
+               pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+               start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
+               for (j = start; j < shinfo->nr_frags; j++) {
+                       pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
+                       xenvif_idx_unmap(vif, pending_idx);
+               }
+       }
+
        *gopp = gop + 1;
        return err;
 }
@@ -965,6 +1009,10 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        int nr_frags = shinfo->nr_frags;
        int i;
+       u16 prev_pending_idx = INVALID_PENDING_IDX;
+
+       if (skb_shinfo(skb)->destructor_arg)
+               prev_pending_idx = XENVIF_TX_CB(skb)->pending_idx;
 
        for (i = 0; i < nr_frags; i++) {
                skb_frag_t *frag = shinfo->frags + i;
@@ -974,6 +1022,17 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
 
                pending_idx = frag_get_pending_idx(frag);
 
+               /* If this is not the first frag, chain it to the previous*/
+               if (unlikely(prev_pending_idx == INVALID_PENDING_IDX))
+                       skb_shinfo(skb)->destructor_arg =
+                               &vif->pending_tx_info[pending_idx].callback_struct;
+               else if (likely(pending_idx != prev_pending_idx))
+                       vif->pending_tx_info[prev_pending_idx].callback_struct.ctx =
+                               &(vif->pending_tx_info[pending_idx].callback_struct);
+
+               vif->pending_tx_info[pending_idx].callback_struct.ctx = NULL;
+               prev_pending_idx = pending_idx;
+
                txp = &vif->pending_tx_info[pending_idx].req;
                page = virt_to_page(idx_to_kaddr(vif, pending_idx));
                __skb_fill_page_desc(skb, i, page, txp->offset, txp->size);
@@ -981,10 +1040,15 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
                skb->data_len += txp->size;
                skb->truesize += txp->size;
 
-               /* Take an extra reference to offset xenvif_idx_release */
+               /* Take an extra reference to offset network stack's put_page */
                get_page(vif->mmap_pages[pending_idx]);
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
        }
+       /* FIXME: __skb_fill_page_desc set this to true because page->pfmemalloc
+        * overlaps with "index", and "mapping" is not set. I think mapping
+        * should be set. If delivered to local stack, it would drop this
+        * skb in sk_filter unless the socket has the right to use it.
+        */
+       skb->pfmemalloc = false;
 }
 
 static int xenvif_get_extras(struct xenvif *vif,
@@ -1104,16 +1168,14 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
 
 static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
 {
-       struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop;
+       struct gnttab_map_grant_ref *gop = vif->tx_map_ops, *request_gop;
        struct sk_buff *skb;
        int ret;
 
-       while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX
-               < MAX_PENDING_REQS) &&
+       while (xenvif_tx_pending_slots_available(vif) &&
               (skb_queue_len(&vif->tx_queue) < budget)) {
                struct xen_netif_tx_request txreq;
                struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX];
-               struct page *page;
                struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
                u16 pending_idx;
                RING_IDX idx;
@@ -1189,8 +1251,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
                            ret < XEN_NETBK_LEGACY_SLOTS_MAX) ?
                        PKT_PROT_LEN : txreq.size;
 
-               skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
-                               GFP_ATOMIC | __GFP_NOWARN);
+               skb = xenvif_alloc_skb(data_len);
                if (unlikely(skb == NULL)) {
                        netdev_dbg(vif->dev,
                                   "Can't allocate a skb in start_xmit.\n");
@@ -1198,9 +1259,6 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
                        break;
                }
 
-               /* Packets passed to netif_rx() must have some headroom. */
-               skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
-
                if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
                        struct xen_netif_extra_info *gso;
                        gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
@@ -1212,31 +1270,11 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
                        }
                }
 
-               /* XXX could copy straight to head */
-               page = xenvif_alloc_page(vif, pending_idx);
-               if (!page) {
-                       kfree_skb(skb);
-                       xenvif_tx_err(vif, &txreq, idx);
-                       break;
-               }
-
-               gop->source.u.ref = txreq.gref;
-               gop->source.domid = vif->domid;
-               gop->source.offset = txreq.offset;
-
-               gop->dest.u.gmfn = virt_to_mfn(page_address(page));
-               gop->dest.domid = DOMID_SELF;
-               gop->dest.offset = txreq.offset;
-
-               gop->len = txreq.size;
-               gop->flags = GNTCOPY_source_gref;
+               xenvif_tx_create_gop(vif, pending_idx, &txreq, gop);
 
                gop++;
 
-               memcpy(&vif->pending_tx_info[pending_idx].req,
-                      &txreq, sizeof(txreq));
-               vif->pending_tx_info[pending_idx].head = index;
-               *((u16 *)skb->data) = pending_idx;
+               XENVIF_TX_CB(skb)->pending_idx = pending_idx;
 
                __skb_put(skb, data_len);
 
@@ -1264,17 +1302,82 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
 
                vif->tx.req_cons = idx;
 
-               if ((gop-vif->tx_copy_ops) >= ARRAY_SIZE(vif->tx_copy_ops))
+               if ((gop-vif->tx_map_ops) >= ARRAY_SIZE(vif->tx_map_ops))
                        break;
        }
 
-       return gop - vif->tx_copy_ops;
+       return gop - vif->tx_map_ops;
 }
 
+/* Consolidate skb with a frag_list into a brand new one with local pages on
+ * frags. Returns 0 or -ENOMEM if can't allocate new pages.
+ */
+static int xenvif_handle_frag_list(struct xenvif *vif, struct sk_buff *skb)
+{
+       unsigned int offset = skb_headlen(skb);
+       skb_frag_t frags[MAX_SKB_FRAGS];
+       int i;
+       struct ubuf_info *uarg;
+       struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
+
+       vif->tx_zerocopy_sent += 2;
+       vif->tx_frag_overflow++;
+
+       xenvif_fill_frags(vif, nskb);
+       /* Subtract frags size, we will correct it later */
+       skb->truesize -= skb->data_len;
+       skb->len += nskb->len;
+       skb->data_len += nskb->len;
+
+       /* create a brand new frags array and coalesce there */
+       for (i = 0; offset < skb->len; i++) {
+               struct page *page;
+               unsigned int len;
+
+               BUG_ON(i >= MAX_SKB_FRAGS);
+               page = alloc_page(GFP_ATOMIC|__GFP_COLD);
+               if (!page) {
+                       int j;
+                       skb->truesize += skb->data_len;
+                       for (j = 0; j < i; j++)
+                               put_page(frags[j].page.p);
+                       return -ENOMEM;
+               }
+
+               if (offset + PAGE_SIZE < skb->len)
+                       len = PAGE_SIZE;
+               else
+                       len = skb->len - offset;
+               if (skb_copy_bits(skb, offset, page_address(page), len))
+                       BUG();
+
+               offset += len;
+               frags[i].page.p = page;
+               frags[i].page_offset = 0;
+               skb_frag_size_set(&frags[i], len);
+       }
+       /* swap out with old one */
+       memcpy(skb_shinfo(skb)->frags,
+              frags,
+              i * sizeof(skb_frag_t));
+       skb_shinfo(skb)->nr_frags = i;
+       skb->truesize += i * PAGE_SIZE;
+
+       /* remove traces of mapped pages and frag_list */
+       skb_frag_list_init(skb);
+       uarg = skb_shinfo(skb)->destructor_arg;
+       uarg->callback(uarg, true);
+       skb_shinfo(skb)->destructor_arg = NULL;
+
+       skb_shinfo(nskb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+       kfree_skb(nskb);
+
+       return 0;
+}
 
 static int xenvif_tx_submit(struct xenvif *vif)
 {
-       struct gnttab_copy *gop = vif->tx_copy_ops;
+       struct gnttab_map_grant_ref *gop = vif->tx_map_ops;
        struct sk_buff *skb;
        int work_done = 0;
 
@@ -1283,7 +1386,7 @@ static int xenvif_tx_submit(struct xenvif *vif)
                u16 pending_idx;
                unsigned data_len;
 
-               pending_idx = *((u16 *)skb->data);
+               pending_idx = XENVIF_TX_CB(skb)->pending_idx;
                txp = &vif->pending_tx_info[pending_idx].req;
 
                /* Check the remap error code. */
@@ -1298,14 +1401,16 @@ static int xenvif_tx_submit(struct xenvif *vif)
                memcpy(skb->data,
                       (void *)(idx_to_kaddr(vif, pending_idx)|txp->offset),
                       data_len);
+               vif->pending_tx_info[pending_idx].callback_struct.ctx = NULL;
                if (data_len < txp->size) {
                        /* Append the packet payload as a fragment. */
                        txp->offset += data_len;
                        txp->size -= data_len;
+                       skb_shinfo(skb)->destructor_arg =
+                               &vif->pending_tx_info[pending_idx].callback_struct;
                } else {
                        /* Schedule a response immediately. */
-                       xenvif_idx_release(vif, pending_idx,
-                                          XEN_NETIF_RSP_OKAY);
+                       xenvif_idx_unmap(vif, pending_idx);
                }
 
                if (txp->flags & XEN_NETTXF_csum_blank)
@@ -1315,6 +1420,17 @@ static int xenvif_tx_submit(struct xenvif *vif)
 
                xenvif_fill_frags(vif, skb);
 
+               if (unlikely(skb_has_frag_list(skb))) {
+                       if (xenvif_handle_frag_list(vif, skb)) {
+                               if (net_ratelimit())
+                                       netdev_err(vif->dev,
+                                                  "Not enough memory to consolidate frag_list!\n");
+                               skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+                               kfree_skb(skb);
+                               continue;
+                       }
+               }
+
                if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) {
                        int target = min_t(int, skb->len, PKT_PROT_LEN);
                        __pskb_pull_tail(skb, target - skb_headlen(skb));
@@ -1327,6 +1443,9 @@ static int xenvif_tx_submit(struct xenvif *vif)
                if (checksum_setup(vif, skb)) {
                        netdev_dbg(vif->dev,
                                   "Can't setup checksum in net_tx_action\n");
+                       /* We have to set this flag to trigger the callback */
+                       if (skb_shinfo(skb)->destructor_arg)
+                               skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
                        kfree_skb(skb);
                        continue;
                }
@@ -1352,17 +1471,134 @@ static int xenvif_tx_submit(struct xenvif *vif)
 
                work_done++;
 
+               /* Set this flag right before netif_receive_skb, otherwise
+                * someone might think this packet already left netback, and
+                * do a skb_copy_ubufs while we are still in control of the
+                * skb. E.g. the __pskb_pull_tail earlier can do such thing.
+                */
+               if (skb_shinfo(skb)->destructor_arg) {
+                       skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+                       vif->tx_zerocopy_sent++;
+               }
+
                netif_receive_skb(skb);
        }
 
        return work_done;
 }
 
+void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success)
+{
+       unsigned long flags;
+       pending_ring_idx_t index;
+       struct xenvif *vif = ubuf_to_vif(ubuf);
+
+       /* This is the only place where we grab this lock, to protect callbacks
+        * from each other.
+        */
+       spin_lock_irqsave(&vif->callback_lock, flags);
+       do {
+               u16 pending_idx = ubuf->desc;
+               ubuf = (struct ubuf_info *) ubuf->ctx;
+               BUG_ON(vif->dealloc_prod - vif->dealloc_cons >=
+                       MAX_PENDING_REQS);
+               index = pending_index(vif->dealloc_prod);
+               vif->dealloc_ring[index] = pending_idx;
+               /* Sync with xenvif_tx_dealloc_action:
+                * insert idx then incr producer.
+                */
+               smp_wmb();
+               vif->dealloc_prod++;
+       } while (ubuf);
+       wake_up(&vif->dealloc_wq);
+       spin_unlock_irqrestore(&vif->callback_lock, flags);
+
+       if (RING_HAS_UNCONSUMED_REQUESTS(&vif->tx) &&
+           xenvif_tx_pending_slots_available(vif)) {
+               local_bh_disable();
+               napi_schedule(&vif->napi);
+               local_bh_enable();
+       }
+
+       if (likely(zerocopy_success))
+               vif->tx_zerocopy_success++;
+       else
+               vif->tx_zerocopy_fail++;
+}
+
+static inline void xenvif_tx_dealloc_action(struct xenvif *vif)
+{
+       struct gnttab_unmap_grant_ref *gop;
+       pending_ring_idx_t dc, dp;
+       u16 pending_idx, pending_idx_release[MAX_PENDING_REQS];
+       unsigned int i = 0;
+
+       dc = vif->dealloc_cons;
+       gop = vif->tx_unmap_ops;
+
+       /* Free up any grants we have finished using */
+       do {
+               dp = vif->dealloc_prod;
+
+               /* Ensure we see all indices enqueued by all
+                * xenvif_zerocopy_callback().
+                */
+               smp_rmb();
+
+               while (dc != dp) {
+                       BUG_ON(gop - vif->tx_unmap_ops > MAX_PENDING_REQS);
+                       pending_idx =
+                               vif->dealloc_ring[pending_index(dc++)];
+
+                       pending_idx_release[gop-vif->tx_unmap_ops] =
+                               pending_idx;
+                       vif->pages_to_unmap[gop-vif->tx_unmap_ops] =
+                               vif->mmap_pages[pending_idx];
+                       gnttab_set_unmap_op(gop,
+                                           idx_to_kaddr(vif, pending_idx),
+                                           GNTMAP_host_map,
+                                           vif->grant_tx_handle[pending_idx]);
+                       /* Btw. already unmapped? */
+                       xenvif_grant_handle_reset(vif, pending_idx);
+                       ++gop;
+               }
+
+       } while (dp != vif->dealloc_prod);
+
+       vif->dealloc_cons = dc;
+
+       if (gop - vif->tx_unmap_ops > 0) {
+               int ret;
+               ret = gnttab_unmap_refs(vif->tx_unmap_ops,
+                                       NULL,
+                                       vif->pages_to_unmap,
+                                       gop - vif->tx_unmap_ops);
+               if (ret) {
+                       netdev_err(vif->dev, "Unmap fail: nr_ops %x ret %d\n",
+                                  gop - vif->tx_unmap_ops, ret);
+                       for (i = 0; i < gop - vif->tx_unmap_ops; ++i) {
+                               if (gop[i].status != GNTST_okay)
+                                       netdev_err(vif->dev,
+                                                  " host_addr: %llx handle: %x status: %d\n",
+                                                  gop[i].host_addr,
+                                                  gop[i].handle,
+                                                  gop[i].status);
+                       }
+                       BUG();
+               }
+       }
+
+       for (i = 0; i < gop - vif->tx_unmap_ops; ++i)
+               xenvif_idx_release(vif, pending_idx_release[i],
+                                  XEN_NETIF_RSP_OKAY);
+}
+
+
 /* Called after netfront has transmitted */
 int xenvif_tx_action(struct xenvif *vif, int budget)
 {
        unsigned nr_gops;
-       int work_done;
+       int work_done, ret;
 
        if (unlikely(!tx_work_todo(vif)))
                return 0;
@@ -1372,7 +1608,11 @@ int xenvif_tx_action(struct xenvif *vif, int budget)
        if (nr_gops == 0)
                return 0;
 
-       gnttab_batch_copy(vif->tx_copy_ops, nr_gops);
+       ret = gnttab_map_refs(vif->tx_map_ops,
+                             NULL,
+                             vif->pages_to_map,
+                             nr_gops);
+       BUG_ON(ret);
 
        work_done = xenvif_tx_submit(vif);
 
@@ -1383,45 +1623,18 @@ static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx,
                               u8 status)
 {
        struct pending_tx_info *pending_tx_info;
-       pending_ring_idx_t head;
-       u16 peek; /* peek into next tx request */
-
-       BUG_ON(vif->mmap_pages[pending_idx] == (void *)(~0UL));
-
-       /* Already complete? */
-       if (vif->mmap_pages[pending_idx] == NULL)
-               return;
+       pending_ring_idx_t index;
+       unsigned long flags;
 
        pending_tx_info = &vif->pending_tx_info[pending_idx];
-
-       head = pending_tx_info->head;
-
-       BUG_ON(!pending_tx_is_head(vif, head));
-       BUG_ON(vif->pending_ring[pending_index(head)] != pending_idx);
-
-       do {
-               pending_ring_idx_t index;
-               pending_ring_idx_t idx = pending_index(head);
-               u16 info_idx = vif->pending_ring[idx];
-
-               pending_tx_info = &vif->pending_tx_info[info_idx];
-               make_tx_response(vif, &pending_tx_info->req, status);
-
-               /* Setting any number other than
-                * INVALID_PENDING_RING_IDX indicates this slot is
-                * starting a new packet / ending a previous packet.
-                */
-               pending_tx_info->head = 0;
-
-               index = pending_index(vif->pending_prod++);
-               vif->pending_ring[index] = vif->pending_ring[info_idx];
-
-               peek = vif->pending_ring[pending_index(++head)];
-
-       } while (!pending_tx_is_head(vif, peek));
-
-       put_page(vif->mmap_pages[pending_idx]);
-       vif->mmap_pages[pending_idx] = NULL;
+       spin_lock_irqsave(&vif->response_lock, flags);
+       make_tx_response(vif, &pending_tx_info->req, status);
+       index = pending_index(vif->pending_prod);
+       vif->pending_ring[index] = pending_idx;
+       /* TX shouldn't use the index before we give it back here */
+       mb();
+       vif->pending_prod++;
+       spin_unlock_irqrestore(&vif->response_lock, flags);
 }
 
 
@@ -1469,23 +1682,74 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
        return resp;
 }
 
+void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx)
+{
+       int ret;
+       struct gnttab_unmap_grant_ref tx_unmap_op;
+
+       gnttab_set_unmap_op(&tx_unmap_op,
+                           idx_to_kaddr(vif, pending_idx),
+                           GNTMAP_host_map,
+                           vif->grant_tx_handle[pending_idx]);
+       /* Btw. already unmapped? */
+       xenvif_grant_handle_reset(vif, pending_idx);
+
+       ret = gnttab_unmap_refs(&tx_unmap_op, NULL,
+                               &vif->mmap_pages[pending_idx], 1);
+       BUG_ON(ret);
+
+       xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
+}
+
 static inline int rx_work_todo(struct xenvif *vif)
 {
-       return !skb_queue_empty(&vif->rx_queue) &&
-              xenvif_rx_ring_slots_available(vif, vif->rx_last_skb_slots);
+       return (!skb_queue_empty(&vif->rx_queue) &&
+              xenvif_rx_ring_slots_available(vif, vif->rx_last_skb_slots)) ||
+              vif->rx_queue_purge;
 }
 
 static inline int tx_work_todo(struct xenvif *vif)
 {
 
        if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)) &&
-           (nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX
-            < MAX_PENDING_REQS))
+           xenvif_tx_pending_slots_available(vif))
                return 1;
 
        return 0;
 }
 
+static void xenvif_dealloc_delay(unsigned long data)
+{
+       struct xenvif *vif = (struct xenvif *)data;
+
+       vif->dealloc_delay_timed_out = true;
+       wake_up(&vif->dealloc_wq);
+}
+
+static inline bool tx_dealloc_work_todo(struct xenvif *vif)
+{
+       if (vif->dealloc_cons != vif->dealloc_prod) {
+               if ((nr_free_slots(&vif->tx) > 2 * XEN_NETBK_LEGACY_SLOTS_MAX) &&
+                   (vif->dealloc_prod - vif->dealloc_cons < MAX_PENDING_REQS / 4) &&
+                   !vif->dealloc_delay_timed_out) {
+                       if (!timer_pending(&vif->dealloc_delay)) {
+                               vif->dealloc_delay.function =
+                                       xenvif_dealloc_delay;
+                               vif->dealloc_delay.data = (unsigned long)vif;
+                               mod_timer(&vif->dealloc_delay,
+                                         jiffies + msecs_to_jiffies(1));
+
+                       }
+                       return false;
+               }
+               del_timer_sync(&vif->dealloc_delay);
+               vif->dealloc_delay_timed_out = false;
+               return true;
+       }
+
+       return false;
+}
+
 void xenvif_unmap_frontend_rings(struct xenvif *vif)
 {
        if (vif->tx.sring)
@@ -1543,7 +1807,7 @@ static void xenvif_start_queue(struct xenvif *vif)
                netif_wake_queue(vif->dev);
 }
 
-int xenvif_kthread(void *data)
+int xenvif_kthread_guest_rx(void *data)
 {
        struct xenvif *vif = data;
        struct sk_buff *skb;
@@ -1555,12 +1819,19 @@ int xenvif_kthread(void *data)
                if (kthread_should_stop())
                        break;
 
+               if (vif->rx_queue_purge) {
+                       skb_queue_purge(&vif->rx_queue);
+                       vif->rx_queue_purge = false;
+               }
+
                if (!skb_queue_empty(&vif->rx_queue))
                        xenvif_rx_action(vif);
 
                if (skb_queue_empty(&vif->rx_queue) &&
-                   netif_queue_stopped(vif->dev))
+                   netif_queue_stopped(vif->dev)) {
+                       del_timer_sync(&vif->wake_queue);
                        xenvif_start_queue(vif);
+               }
 
                cond_resched();
        }
@@ -1572,6 +1843,28 @@ int xenvif_kthread(void *data)
        return 0;
 }
 
+int xenvif_dealloc_kthread(void *data)
+{
+       struct xenvif *vif = data;
+
+       while (!kthread_should_stop()) {
+               wait_event_interruptible(vif->dealloc_wq,
+                                        tx_dealloc_work_todo(vif) ||
+                                        kthread_should_stop());
+               if (kthread_should_stop())
+                       break;
+
+               xenvif_tx_dealloc_action(vif);
+               cond_resched();
+       }
+
+       /* Unmap anything remaining*/
+       if (tx_dealloc_work_todo(vif))
+               xenvif_tx_dealloc_action(vif);
+
+       return 0;
+}
+
 static int __init netback_init(void)
 {
        int rc = 0;
@@ -1589,6 +1882,8 @@ static int __init netback_init(void)
        if (rc)
                goto failed_init;
 
+       rx_drain_timeout_jiffies = msecs_to_jiffies(rx_drain_timeout_msecs);
+
        return 0;
 
 failed_init:
index 2b62d799bfd8ee2f6d90a0f72237794e7b7531cb..49f3b3dbbed8aab42a406445c5db8a1272fcc1e9 100644 (file)
@@ -907,6 +907,7 @@ static int handle_incoming_queue(struct net_device *dev,
 
                /* Ethernet work: Delayed to here as it peeks the header. */
                skb->protocol = eth_type_trans(skb, dev);
+               skb_reset_network_header(skb);
 
                if (checksum_setup(dev, skb)) {
                        kfree_skb(skb);
@@ -1059,13 +1060,13 @@ static struct rtnl_link_stats64 *xennet_get_stats64(struct net_device *dev,
                unsigned int start;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&stats->syncp);
 
                        rx_packets = stats->rx_packets;
                        tx_packets = stats->tx_packets;
                        rx_bytes = stats->rx_bytes;
                        tx_bytes = stats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
 
                tot->rx_packets += rx_packets;
                tot->tx_packets += tx_packets;
index 10b51106c854f20fc1b73bf80d9b5c37d23d8545..89e888a78899e2b61281f7007406e5f937cc28a0 100644 (file)
@@ -342,27 +342,72 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
 }
 EXPORT_SYMBOL(of_get_cpu_node);
 
-/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
+/**
+ * __of_device_is_compatible() - Check if the node matches given constraints
+ * @device: pointer to node
+ * @compat: required compatible string, NULL or "" for any match
+ * @type: required device_type value, NULL or "" for any match
+ * @name: required node name, NULL or "" for any match
+ *
+ * Checks if the given @compat, @type and @name strings match the
+ * properties of the given @device. A constraints can be skipped by
+ * passing NULL or an empty string as the constraint.
+ *
+ * Returns 0 for no match, and a positive integer on match. The return
+ * value is a relative score with larger values indicating better
+ * matches. The score is weighted for the most specific compatible value
+ * to get the highest score. Matching type is next, followed by matching
+ * name. Practically speaking, this results in the following priority
+ * order for matches:
+ *
+ * 1. specific compatible && type && name
+ * 2. specific compatible && type
+ * 3. specific compatible && name
+ * 4. specific compatible
+ * 5. general compatible && type && name
+ * 6. general compatible && type
+ * 7. general compatible && name
+ * 8. general compatible
+ * 9. type && name
+ * 10. type
+ * 11. name
  */
 static int __of_device_is_compatible(const struct device_node *device,
-                                    const char *compat)
+                                    const char *compat, const char *type, const char *name)
 {
-       const char* cp;
-       int cplen, l;
+       struct property *prop;
+       const char *cp;
+       int index = 0, score = 0;
+
+       /* Compatible match has highest priority */
+       if (compat && compat[0]) {
+               prop = __of_find_property(device, "compatible", NULL);
+               for (cp = of_prop_next_string(prop, NULL); cp;
+                    cp = of_prop_next_string(prop, cp), index++) {
+                       if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
+                               score = INT_MAX/2 - (index << 2);
+                               break;
+                       }
+               }
+               if (!score)
+                       return 0;
+       }
 
-       cp = __of_get_property(device, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
+       /* Matching type is better than matching name */
+       if (type && type[0]) {
+               if (!device->type || of_node_cmp(type, device->type))
+                       return 0;
+               score += 2;
        }
 
-       return 0;
+       /* Matching name is a bit better than not */
+       if (name && name[0]) {
+               if (!device->name || of_node_cmp(name, device->name))
+                       return 0;
+               score++;
+       }
+
+       return score;
 }
 
 /** Checks if the given "compat" string matches one of the strings in
@@ -375,7 +420,7 @@ int of_device_is_compatible(const struct device_node *device,
        int res;
 
        raw_spin_lock_irqsave(&devtree_lock, flags);
-       res = __of_device_is_compatible(device, compat);
+       res = __of_device_is_compatible(device, compat, NULL, NULL);
        raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return res;
 }
@@ -681,10 +726,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
        raw_spin_lock_irqsave(&devtree_lock, flags);
        np = from ? from->allnext : of_allnodes;
        for (; np; np = np->allnext) {
-               if (type
-                   && !(np->type && (of_node_cmp(np->type, type) == 0)))
-                       continue;
-               if (__of_device_is_compatible(np, compatible) &&
+               if (__of_device_is_compatible(np, compatible, type, NULL) &&
                    of_node_get(np))
                        break;
        }
@@ -730,65 +772,26 @@ out:
 }
 EXPORT_SYMBOL(of_find_node_with_property);
 
-static const struct of_device_id *
-of_match_compatible(const struct of_device_id *matches,
-                       const struct device_node *node)
-{
-       const char *cp;
-       int cplen, l;
-       const struct of_device_id *m;
-
-       cp = __of_get_property(node, "compatible", &cplen);
-       while (cp && (cplen > 0)) {
-               m = matches;
-               while (m->name[0] || m->type[0] || m->compatible[0]) {
-                       /* Only match for the entries without type and name */
-                       if (m->name[0] || m->type[0] ||
-                               of_compat_cmp(m->compatible, cp,
-                                        strlen(m->compatible)))
-                               m++;
-                       else
-                               return m;
-               }
-
-               /* Get node's next compatible string */
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return NULL;
-}
-
 static
 const struct of_device_id *__of_match_node(const struct of_device_id *matches,
                                           const struct device_node *node)
 {
-       const struct of_device_id *m;
+       const struct of_device_id *best_match = NULL;
+       int score, best_score = 0;
 
        if (!matches)
                return NULL;
 
-       m = of_match_compatible(matches, node);
-       if (m)
-               return m;
-
-       while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-               int match = 1;
-               if (matches->name[0])
-                       match &= node->name
-                               && !strcmp(matches->name, node->name);
-               if (matches->type[0])
-                       match &= node->type
-                               && !strcmp(matches->type, node->type);
-               if (matches->compatible[0])
-                       match &= __of_device_is_compatible(node,
-                                                          matches->compatible);
-               if (match)
-                       return matches;
-               matches++;
+       for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
+               score = __of_device_is_compatible(node, matches->compatible,
+                                                 matches->type, matches->name);
+               if (score > best_score) {
+                       best_match = matches;
+                       best_score = score;
+               }
        }
-       return NULL;
+
+       return best_match;
 }
 
 /**
@@ -796,12 +799,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
  *     @matches:       array of of device match structures to search in
  *     @node:          the of device structure to match against
  *
- *     Low level utility function used by device matching. We have two ways
- *     of matching:
- *     - Try to find the best compatible match by comparing each compatible
- *       string of device node with all the given matches respectively.
- *     - If the above method failed, then try to match the compatible by using
- *       __of_device_is_compatible() besides the match in type and name.
+ *     Low level utility function used by device matching.
  */
 const struct of_device_id *of_match_node(const struct of_device_id *matches,
                                         const struct device_node *node)
index e21012bde639cde305a8c14aab011fad020a7da2..6643d19209857dae4f6d2d1f9a3033280e2cc25e 100644 (file)
@@ -300,6 +300,72 @@ static void __init of_selftest_parse_interrupts_extended(void)
        of_node_put(np);
 }
 
+static struct of_device_id match_node_table[] = {
+       { .data = "A", .name = "name0", }, /* Name alone is lowest priority */
+       { .data = "B", .type = "type1", }, /* followed by type alone */
+
+       { .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */
+       { .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */
+       { .data = "Cc", .name = "name2", .type = "type2", },
+
+       { .data = "E", .compatible = "compat3" },
+       { .data = "G", .compatible = "compat2", },
+       { .data = "H", .compatible = "compat2", .name = "name5", },
+       { .data = "I", .compatible = "compat2", .type = "type1", },
+       { .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", },
+       { .data = "K", .compatible = "compat2", .name = "name9", },
+       {}
+};
+
+static struct {
+       const char *path;
+       const char *data;
+} match_node_tests[] = {
+       { .path = "/testcase-data/match-node/name0", .data = "A", },
+       { .path = "/testcase-data/match-node/name1", .data = "B", },
+       { .path = "/testcase-data/match-node/a/name2", .data = "Ca", },
+       { .path = "/testcase-data/match-node/b/name2", .data = "Cb", },
+       { .path = "/testcase-data/match-node/c/name2", .data = "Cc", },
+       { .path = "/testcase-data/match-node/name3", .data = "E", },
+       { .path = "/testcase-data/match-node/name4", .data = "G", },
+       { .path = "/testcase-data/match-node/name5", .data = "H", },
+       { .path = "/testcase-data/match-node/name6", .data = "G", },
+       { .path = "/testcase-data/match-node/name7", .data = "I", },
+       { .path = "/testcase-data/match-node/name8", .data = "J", },
+       { .path = "/testcase-data/match-node/name9", .data = "K", },
+};
+
+static void __init of_selftest_match_node(void)
+{
+       struct device_node *np;
+       const struct of_device_id *match;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) {
+               np = of_find_node_by_path(match_node_tests[i].path);
+               if (!np) {
+                       selftest(0, "missing testcase node %s\n",
+                               match_node_tests[i].path);
+                       continue;
+               }
+
+               match = of_match_node(match_node_table, np);
+               if (!match) {
+                       selftest(0, "%s didn't match anything\n",
+                               match_node_tests[i].path);
+                       continue;
+               }
+
+               if (strcmp(match->data, match_node_tests[i].data) != 0) {
+                       selftest(0, "%s got wrong match. expected %s, got %s\n",
+                               match_node_tests[i].path, match_node_tests[i].data,
+                               (const char *)match->data);
+                       continue;
+               }
+               selftest(1, "passed");
+       }
+}
+
 static int __init of_selftest(void)
 {
        struct device_node *np;
@@ -316,6 +382,7 @@ static int __init of_selftest(void)
        of_selftest_property_match_string();
        of_selftest_parse_interrupts();
        of_selftest_parse_interrupts_extended();
+       of_selftest_match_node();
        pr_info("end of selftest - %i passed, %i failed\n",
                selftest_results.passed, selftest_results.failed);
        return 0;
diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dtsi
new file mode 100644 (file)
index 0000000..3a5b75a
--- /dev/null
@@ -0,0 +1,3 @@
+#include "tests-phandle.dtsi"
+#include "tests-interrupts.dtsi"
+#include "tests-match.dtsi"
diff --git a/drivers/of/testcase-data/tests-interrupts.dtsi b/drivers/of/testcase-data/tests-interrupts.dtsi
new file mode 100644 (file)
index 0000000..c843720
--- /dev/null
@@ -0,0 +1,58 @@
+
+/ {
+       testcase-data {
+               interrupts {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       test_intc0: intc0 {
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+                       test_intc1: intc1 {
+                               interrupt-controller;
+                               #interrupt-cells = <3>;
+                       };
+
+                       test_intc2: intc2 {
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       test_intmap0: intmap0 {
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               interrupt-map = <1 &test_intc0 9>,
+                                               <2 &test_intc1 10 11 12>,
+                                               <3 &test_intc2 13 14>,
+                                               <4 &test_intc2 15 16>;
+                       };
+
+                       test_intmap1: intmap1 {
+                               #interrupt-cells = <2>;
+                               interrupt-map = <0x5000 1 2 &test_intc0 15>;
+                       };
+
+                       interrupts0 {
+                               interrupt-parent = <&test_intc0>;
+                               interrupts = <1>, <2>, <3>, <4>;
+                       };
+
+                       interrupts1 {
+                               interrupt-parent = <&test_intmap0>;
+                               interrupts = <1>, <2>, <3>, <4>;
+                       };
+
+                       interrupts-extended0 {
+                               reg = <0x5000 0x100>;
+                               interrupts-extended = <&test_intc0 1>,
+                                                     <&test_intc1 2 3 4>,
+                                                     <&test_intc2 5 6>,
+                                                     <&test_intmap0 1>,
+                                                     <&test_intmap0 2>,
+                                                     <&test_intmap0 3>,
+                                                     <&test_intmap1 1 2>;
+                       };
+               };
+       };
+};
diff --git a/drivers/of/testcase-data/tests-match.dtsi b/drivers/of/testcase-data/tests-match.dtsi
new file mode 100644 (file)
index 0000000..c9e5411
--- /dev/null
@@ -0,0 +1,19 @@
+
+/ {
+       testcase-data {
+               match-node {
+                       name0 { };
+                       name1 { device_type = "type1"; };
+                       a { name2 { device_type = "type1"; }; };
+                       b { name2 { }; };
+                       c { name2 { device_type = "type2"; }; };
+                       name3 { compatible = "compat3"; };
+                       name4 { compatible = "compat2", "compat3"; };
+                       name5 { compatible = "compat2", "compat3"; };
+                       name6 { compatible = "compat1", "compat2", "compat3"; };
+                       name7 { compatible = "compat2"; device_type = "type1"; };
+                       name8 { compatible = "compat2"; device_type = "type1"; };
+                       name9 { compatible = "compat2"; };
+               };
+       };
+};
diff --git a/drivers/of/testcase-data/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi
new file mode 100644 (file)
index 0000000..0007d3c
--- /dev/null
@@ -0,0 +1,39 @@
+
+/ {
+       testcase-data {
+               phandle-tests {
+                       provider0: provider0 {
+                               #phandle-cells = <0>;
+                       };
+
+                       provider1: provider1 {
+                               #phandle-cells = <1>;
+                       };
+
+                       provider2: provider2 {
+                               #phandle-cells = <2>;
+                       };
+
+                       provider3: provider3 {
+                               #phandle-cells = <3>;
+                       };
+
+                       consumer-a {
+                               phandle-list =  <&provider1 1>,
+                                               <&provider2 2 0>,
+                                               <0>,
+                                               <&provider3 4 4 3>,
+                                               <&provider2 5 100>,
+                                               <&provider0>,
+                                               <&provider1 7>;
+                               phandle-list-names = "first", "second", "third";
+
+                               phandle-list-bad-phandle = <12345678 0 0>;
+                               phandle-list-bad-args = <&provider2 1 0>,
+                                                       <&provider3 0>;
+                               empty-property;
+                               unterminated-string = [40 41 42 43];
+                       };
+               };
+       };
+};
index 00660cc502c5e0df1da9946281ba2b6fa6d08afc..38901665c77086a20a6bd1cd087f24971c0d172b 100644 (file)
@@ -162,8 +162,6 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
 
                avail = *r;
                pci_clip_resource_to_region(bus, &avail, region);
-               if (!resource_size(&avail))
-                       continue;
 
                /*
                 * "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to
index 13478ecd411306115b666a9e344754966ce3012b..0e79665afd445ebb8e6198a274960978c58c619e 100644 (file)
 #define PCIE_DEBUG_CTRL         0x1a60
 #define  PCIE_DEBUG_SOFT_RESET         BIT(20)
 
-/*
- * This product ID is registered by Marvell, and used when the Marvell
- * SoC is not the root complex, but an endpoint on the PCIe bus. It is
- * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI
- * bridge.
- */
-#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846
-
 /* PCI configuration space of a PCI-to-PCI bridge */
 struct mvebu_sw_pci_bridge {
        u16 vendor;
@@ -388,7 +380,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
 
        bridge->class = PCI_CLASS_BRIDGE_PCI;
        bridge->vendor = PCI_VENDOR_ID_MARVELL;
-       bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
+       bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
+       bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;
        bridge->header_type = PCI_HEADER_TYPE_BRIDGE;
        bridge->cache_line_size = 0x10;
 
index 7a0fec6ce5717baac5ef564c743d129cbc03a892..955ab7990c5bd7045f2bf896e6d4c65989176089 100644 (file)
@@ -545,9 +545,15 @@ static int populate_msi_sysfs(struct pci_dev *pdev)
                return -ENOMEM;
        list_for_each_entry(entry, &pdev->msi_list, list) {
                char *name = kmalloc(20, GFP_KERNEL);
+               if (!name)
+                       goto error_attrs;
+
                msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
-               if (!msi_dev_attr)
+               if (!msi_dev_attr) {
+                       kfree(name);
                        goto error_attrs;
+               }
+
                sprintf(name, "%d", entry->irq);
                sysfs_attr_init(&msi_dev_attr->attr);
                msi_dev_attr->attr.name = name;
@@ -589,6 +595,7 @@ error_attrs:
                ++count;
                msi_attr = msi_attrs[count];
        }
+       kfree(msi_attrs);
        return ret;
 }
 
@@ -959,7 +966,6 @@ EXPORT_SYMBOL(pci_disable_msi);
 /**
  * pci_msix_vec_count - return the number of device's MSI-X table entries
  * @dev: pointer to the pci_dev data structure of MSI-X device function
-
  * This function returns the number of device's MSI-X table entries and
  * therefore the number of MSI-X vectors device is capable of sending.
  * It returns a negative errno if the device is not capable of sending MSI-X
index 1febe90831b442303b7414faec770d4850ca53ed..fdbc294821e6468d55ca7d5fd68162b407607e97 100644 (file)
@@ -1181,6 +1181,8 @@ EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state);
 static int do_pci_enable_device(struct pci_dev *dev, int bars)
 {
        int err;
+       u16 cmd;
+       u8 pin;
 
        err = pci_set_power_state(dev, PCI_D0);
        if (err < 0 && err != -EIO)
@@ -1190,6 +1192,17 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
                return err;
        pci_fixup_device(pci_fixup_enable, dev);
 
+       if (dev->msi_enabled || dev->msix_enabled)
+               return 0;
+
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (pin) {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               if (cmd & PCI_COMMAND_INTX_DISABLE)
+                       pci_write_config_word(dev, PCI_COMMAND,
+                                             cmd & ~PCI_COMMAND_INTX_DISABLE);
+       }
+
        return 0;
 }
 
index afa2354f6600e72d904ea907ee92f775010ae8a9..c7a551c2d5f1b4d39b982d85222537ec3fbfb804 100644 (file)
@@ -5,7 +5,7 @@
 menu "PHY Subsystem"
 
 config GENERIC_PHY
-       tristate "PHY Core"
+       bool "PHY Core"
        help
          Generic PHY support.
 
@@ -61,6 +61,7 @@ config PHY_EXYNOS_DP_VIDEO
 config BCM_KONA_USB2_PHY
        tristate "Broadcom Kona USB2 PHY Driver"
        depends on GENERIC_PHY
+       depends on HAS_IOMEM
        help
          Enable this to support the Broadcom Kona USB 2.0 PHY.
 
index 5f5b0f4be5be3da4e3146f4479d416306f4de9e9..6c738376daff5110a791c3c3f6492ab818971165 100644 (file)
@@ -176,6 +176,8 @@ int phy_init(struct phy *phy)
                        dev_err(&phy->dev, "phy init failed --> %d\n", ret);
                        goto out;
                }
+       } else {
+               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->init_count;
 
@@ -232,6 +234,8 @@ int phy_power_on(struct phy *phy)
                        dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
                        goto out;
                }
+       } else {
+               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->power_count;
        mutex_unlock(&phy->mutex);
@@ -404,17 +408,11 @@ struct phy *phy_get(struct device *dev, const char *string)
                index = of_property_match_string(dev->of_node, "phy-names",
                        string);
                phy = of_phy_get(dev, index);
-               if (IS_ERR(phy)) {
-                       dev_err(dev, "unable to find phy\n");
-                       return phy;
-               }
        } else {
                phy = phy_lookup(dev, string);
-               if (IS_ERR(phy)) {
-                       dev_err(dev, "unable to find phy\n");
-                       return phy;
-               }
        }
+       if (IS_ERR(phy))
+               return phy;
 
        if (!try_module_get(phy->ops->owner))
                return ERR_PTR(-EPROBE_DEFER);
index 1dbe6ce7b2ce795e0a81ec3a632a8b6d6927f2bc..0786fef842e7fd878507d4342074db65b942c47b 100644 (file)
@@ -76,10 +76,6 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
        if (IS_ERR(state->regs))
                return PTR_ERR(state->regs);
 
-       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        phy = devm_phy_create(dev, &exynos_dp_video_phy_ops, NULL);
        if (IS_ERR(phy)) {
                dev_err(dev, "failed to create Display Port PHY\n");
@@ -87,6 +83,10 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
        }
        phy_set_drvdata(phy, state);
 
+       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        return 0;
 }
 
index 0c5efab11af18a5b2b7367014747e0b34984b585..7f139326a6424e8b38d5fdd9049f26d85e679e6c 100644 (file)
@@ -134,11 +134,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
        dev_set_drvdata(dev, state);
        spin_lock_init(&state->slock);
 
-       phy_provider = devm_of_phy_provider_register(dev,
-                                       exynos_mipi_video_phy_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
                struct phy *phy = devm_phy_create(dev,
                                        &exynos_mipi_video_phy_ops, NULL);
@@ -152,6 +147,11 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
                phy_set_drvdata(phy, &state->phys[i]);
        }
 
+       phy_provider = devm_of_phy_provider_register(dev,
+                                       exynos_mipi_video_phy_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        return 0;
 }
 
index d43786f6243742ed378fb1b7d3c6756fd111381d..d70ecd6a1b3f51e60077559159912e2564e6b1a1 100644 (file)
@@ -99,17 +99,17 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev)
        if (IS_ERR(priv->clk))
                return PTR_ERR(priv->clk);
 
-       phy_provider = devm_of_phy_provider_register(&pdev->dev,
-                                                    of_phy_simple_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops, NULL);
        if (IS_ERR(phy))
                return PTR_ERR(phy);
 
        phy_set_drvdata(phy, priv);
 
+       phy_provider = devm_of_phy_provider_register(&pdev->dev,
+                                                    of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        /* The boot loader may of left it on. Turn it off. */
        phy_mvebu_sata_power_off(phy);
 
index bfc5c337f99a8178278d9aa8f0b9b7be74f41889..7699752fba11bfbfa8acff589d794262d2882cc4 100644 (file)
@@ -177,11 +177,6 @@ static int omap_usb2_probe(struct platform_device *pdev)
        phy->phy.otg            = otg;
        phy->phy.type           = USB_PHY_TYPE_USB2;
 
-       phy_provider = devm_of_phy_provider_register(phy->dev,
-                       of_phy_simple_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        control_node = of_parse_phandle(node, "ctrl-module", 0);
        if (!control_node) {
                dev_err(&pdev->dev, "Failed to get control device phandle\n");
@@ -214,6 +209,11 @@ static int omap_usb2_probe(struct platform_device *pdev)
 
        phy_set_drvdata(generic_phy, phy);
 
+       phy_provider = devm_of_phy_provider_register(phy->dev,
+                       of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
        if (IS_ERR(phy->wkupclk)) {
                dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
index daf65e68aaab53c663847e05d2dcf1fbdb035544..c3ace1db8136eedef379691bc6fa532b4ff5d67c 100644 (file)
@@ -695,11 +695,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        otg->set_host           = twl4030_set_host;
        otg->set_peripheral     = twl4030_set_peripheral;
 
-       phy_provider = devm_of_phy_provider_register(twl->dev,
-               of_phy_simple_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        phy = devm_phy_create(twl->dev, &ops, init_data);
        if (IS_ERR(phy)) {
                dev_dbg(&pdev->dev, "Failed to create PHY\n");
@@ -708,6 +703,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
 
        phy_set_drvdata(phy, twl);
 
+       phy_provider = devm_of_phy_provider_register(twl->dev,
+               of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        /* init spinlock for workqueue */
        spin_lock_init(&twl->lock);
 
index be361b7cd30f240e4b1a78abbb3acd253620b035..1e4e69384baaed11ae859ce6a784eef0d8fa0f9c 100644 (file)
@@ -217,7 +217,7 @@ config PINCTRL_IMX28
        select PINCTRL_MXS
 
 config PINCTRL_MSM
-       tristate
+       bool
        select PINMUX
        select PINCONF
        select GENERIC_PINCONF
index 4669c53f99b0a4fc8e30ab4678263be292f014fd..eb2500212147bdc72177f3e67c31ed23f7e6ea6a 100644 (file)
@@ -1435,7 +1435,7 @@ int __init capri_pinctrl_probe(struct platform_device *pdev)
 }
 
 static struct of_device_id capri_pinctrl_of_match[] = {
-       { .compatible = "brcm,capri-pinctrl", },
+       { .compatible = "brcm,bcm11351-pinctrl", },
        { },
 };
 
index 9ccf681dad2f4993cdf3ef20a9099a17ae62dcb9..f9fabe9bf47d433b9152cd438e259e568b3b9ff5 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -584,7 +585,7 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
        spin_lock_irqsave(&pctl->lock, flags);
 
        regval = readl(pctl->membase + reg);
-       regval &= ~IRQ_CFG_IRQ_MASK;
+       regval &= ~(IRQ_CFG_IRQ_MASK << index);
        writel(regval | (mode << index), pctl->membase + reg);
 
        spin_unlock_irqrestore(&pctl->lock, flags);
@@ -665,6 +666,7 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
 
 static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
 {
+       struct irq_chip *chip = irq_get_chip(irq);
        struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
        const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
 
@@ -674,10 +676,12 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
        if (reg) {
                int irqoffset;
 
+               chained_irq_enter(chip, desc);
                for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
                        int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
                        generic_handle_irq(pin_irq);
                }
+               chained_irq_exit(chip, desc);
        }
 }
 
index 01c494f8a14f0119493d783624b86831549ccdb0..552b0e97077a858b0c1aeda6d9f1a83e4803ae35 100644 (file)
@@ -511,7 +511,7 @@ static inline u32 sunxi_pull_offset(u16 pin)
 
 static inline u32 sunxi_irq_cfg_reg(u16 irq)
 {
-       u8 reg = irq / IRQ_CFG_IRQ_PER_REG;
+       u8 reg = irq / IRQ_CFG_IRQ_PER_REG * 0x04;
        return reg + IRQ_CFG_REG;
 }
 
@@ -523,7 +523,7 @@ static inline u32 sunxi_irq_cfg_offset(u16 irq)
 
 static inline u32 sunxi_irq_ctrl_reg(u16 irq)
 {
-       u8 reg = irq / IRQ_CTRL_IRQ_PER_REG;
+       u8 reg = irq / IRQ_CTRL_IRQ_PER_REG * 0x04;
        return reg + IRQ_CTRL_REG;
 }
 
@@ -535,7 +535,7 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
 
 static inline u32 sunxi_irq_status_reg(u16 irq)
 {
-       u8 reg = irq / IRQ_STATUS_IRQ_PER_REG;
+       u8 reg = irq / IRQ_STATUS_IRQ_PER_REG * 0x04;
        return reg + IRQ_STATUS_REG;
 }
 
index 77d103fe39d90c8ad0bb82485ec1896dd1b5889a..567d6918d50b226b7841c84a98b2343ad552a03e 100644 (file)
@@ -89,7 +89,8 @@ enum {
 
        /* GPSR6 */
        FN_IP13_10, FN_IP13_11, FN_IP13_12, FN_IP13_13, FN_IP13_14,
-       FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19, FN_IP13_22, FN_IP13_24_23,
+       FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19,
+       FN_IP13_22, FN_IP13_24_23, FN_SD1_CLK,
        FN_IP13_25, FN_IP13_26, FN_IP13_27, FN_IP13_30_28, FN_IP14_1_0,
        FN_IP14_2, FN_IP14_3, FN_IP14_4, FN_IP14_5, FN_IP14_6, FN_IP14_7,
        FN_IP14_10_8, FN_IP14_13_11, FN_IP14_16_14, FN_IP14_19_17,
@@ -788,6 +789,7 @@ static const u16 pinmux_data[] = {
        PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
        PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
        PINMUX_DATA(DU0_DOTCLKIN_MARK, FN_DU0_DOTCLKIN),
+       PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
 
        /* IPSR0 */
        PINMUX_IPSR_DATA(IP0_0, D0),
@@ -3825,7 +3827,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
                GP_6_11_FN, FN_IP13_25,
                GP_6_10_FN, FN_IP13_24_23,
                GP_6_9_FN, FN_IP13_22,
-               0, 0,
+               GP_6_8_FN, FN_SD1_CLK,
                GP_6_7_FN, FN_IP13_21_19,
                GP_6_6_FN, FN_IP13_18_16,
                GP_6_5_FN, FN_IP13_15,
index a0d6152701cdf3d3aa5a64bbb435f93526d0a324..617a4916b50fc1d8fec129e001f717c00de13880 100644 (file)
@@ -598,7 +598,7 @@ static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d)
 {
        struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
 
-       if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq))
+       if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE))
                dev_err(bank->chip.gc.dev,
                        "unable to lock HW IRQ %lu for IRQ\n",
                        d->hwirq);
@@ -611,7 +611,7 @@ static void sirfsoc_gpio_irq_shutdown(struct irq_data *d)
        struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
 
        sirfsoc_gpio_irq_mask(d);
-       gpio_unlock_as_irq(&bank->chip.gc, d->hwirq);
+       gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
 }
 
 static struct irq_chip sirfsoc_irq_chip = {
index 167f3d00c916d2e30a63dcc31d260a45d1e5cada..66977ebf13b30cba09b6bb1b7c06eeb07e2e5bd0 100644 (file)
@@ -183,9 +183,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
        struct resource r = {0};
        int i, flags;
 
-       if (acpi_dev_resource_memory(res, &r)
-           || acpi_dev_resource_io(res, &r)
-           || acpi_dev_resource_address_space(res, &r)
+       if (acpi_dev_resource_address_space(res, &r)
            || acpi_dev_resource_ext_address_space(res, &r)) {
                pnp_add_resource(dev, &r);
                return AE_OK;
@@ -217,6 +215,17 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
        }
 
        switch (res->type) {
+       case ACPI_RESOURCE_TYPE_MEMORY24:
+       case ACPI_RESOURCE_TYPE_MEMORY32:
+       case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+               if (acpi_dev_resource_memory(res, &r))
+                       pnp_add_resource(dev, &r);
+               break;
+       case ACPI_RESOURCE_TYPE_IO:
+       case ACPI_RESOURCE_TYPE_FIXED_IO:
+               if (acpi_dev_resource_io(res, &r))
+                       pnp_add_resource(dev, &r);
+               break;
        case ACPI_RESOURCE_TYPE_DMA:
                dma = &res->data.dma;
                if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
index 8a843a04c22456bb5c9856a92aba876c03beeca9..a40b9c34e9fffcd2bce08169cd7a256de067027f 100644 (file)
@@ -52,8 +52,10 @@ lp3943_pwm_request_map(struct lp3943_pwm *lp3943_pwm, int hwpwm)
                offset = pwm_map->output[i];
 
                /* Return an error if the pin is already assigned */
-               if (test_and_set_bit(offset, &lp3943->pin_used))
+               if (test_and_set_bit(offset, &lp3943->pin_used)) {
+                       kfree(pwm_map);
                        return ERR_PTR(-EBUSY);
+               }
        }
 
        return pwm_map;
index b4b0d83f9ef6437dfb97f33037aaee1acf7bda59..7061ac0ad4287c0d84edb39058ef6abc295e43ce 100644 (file)
@@ -678,6 +678,7 @@ struct tsi721_bdma_chan {
        struct list_head        free_list;
        dma_cookie_t            completed_cookie;
        struct tasklet_struct   tasklet;
+       bool                    active;
 };
 
 #endif /* CONFIG_RAPIDIO_DMA_ENGINE */
index 502663f5f7c65a847f45881dcac4821081a314cf..91245f5dbe81a7d235f13a2dd2edbe741508d584 100644 (file)
@@ -206,8 +206,8 @@ void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan)
 {
        /* Disable BDMA channel interrupts */
        iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE);
-
-       tasklet_schedule(&bdma_chan->tasklet);
+       if (bdma_chan->active)
+               tasklet_schedule(&bdma_chan->tasklet);
 }
 
 #ifdef CONFIG_PCI_MSI
@@ -562,7 +562,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
        }
 #endif /* CONFIG_PCI_MSI */
 
-       tasklet_enable(&bdma_chan->tasklet);
+       bdma_chan->active = true;
        tsi721_bdma_interrupt_enable(bdma_chan, 1);
 
        return bdma_chan->bd_num - 1;
@@ -576,9 +576,7 @@ err_out:
 static void tsi721_free_chan_resources(struct dma_chan *dchan)
 {
        struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan);
-#ifdef CONFIG_PCI_MSI
        struct tsi721_device *priv = to_tsi721(dchan->device);
-#endif
        LIST_HEAD(list);
 
        dev_dbg(dchan->device->dev, "%s: Entry\n", __func__);
@@ -589,14 +587,25 @@ static void tsi721_free_chan_resources(struct dma_chan *dchan)
        BUG_ON(!list_empty(&bdma_chan->active_list));
        BUG_ON(!list_empty(&bdma_chan->queue));
 
-       tasklet_disable(&bdma_chan->tasklet);
+       tsi721_bdma_interrupt_enable(bdma_chan, 0);
+       bdma_chan->active = false;
+
+#ifdef CONFIG_PCI_MSI
+       if (priv->flags & TSI721_USING_MSIX) {
+               synchronize_irq(priv->msix[TSI721_VECT_DMA0_DONE +
+                                          bdma_chan->id].vector);
+               synchronize_irq(priv->msix[TSI721_VECT_DMA0_INT +
+                                          bdma_chan->id].vector);
+       } else
+#endif
+       synchronize_irq(priv->pdev->irq);
+
+       tasklet_kill(&bdma_chan->tasklet);
 
        spin_lock_bh(&bdma_chan->lock);
        list_splice_init(&bdma_chan->free_list, &list);
        spin_unlock_bh(&bdma_chan->lock);
 
-       tsi721_bdma_interrupt_enable(bdma_chan, 0);
-
 #ifdef CONFIG_PCI_MSI
        if (priv->flags & TSI721_USING_MSIX) {
                free_irq(priv->msix[TSI721_VECT_DMA0_DONE +
@@ -790,6 +799,7 @@ int tsi721_register_dma(struct tsi721_device *priv)
                bdma_chan->dchan.cookie = 1;
                bdma_chan->dchan.chan_id = i;
                bdma_chan->id = i;
+               bdma_chan->active = false;
 
                spin_lock_init(&bdma_chan->lock);
 
@@ -799,7 +809,6 @@ int tsi721_register_dma(struct tsi721_device *priv)
 
                tasklet_init(&bdma_chan->tasklet, tsi721_dma_tasklet,
                             (unsigned long)bdma_chan);
-               tasklet_disable(&bdma_chan->tasklet);
                list_add_tail(&bdma_chan->dchan.device_node,
                              &mport->dma.channels);
        }
index 16a309e5c024ed45b4276d13d1f8e14c2c0a131c..afca1bc24f262251abf3352d2e09d6452959805b 100644 (file)
@@ -953,6 +953,8 @@ static int machine_constraints_current(struct regulator_dev *rdev,
        return 0;
 }
 
+static int _regulator_do_enable(struct regulator_dev *rdev);
+
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -1013,10 +1015,9 @@ static int set_machine_constraints(struct regulator_dev *rdev,
        /* If the constraints say the regulator should be on at this point
         * and we have control then make sure it is enabled.
         */
-       if ((rdev->constraints->always_on || rdev->constraints->boot_on) &&
-           ops->enable) {
-               ret = ops->enable(rdev);
-               if (ret < 0) {
+       if (rdev->constraints->always_on || rdev->constraints->boot_on) {
+               ret = _regulator_do_enable(rdev);
+               if (ret < 0 && ret != -EINVAL) {
                        rdev_err(rdev, "failed to enable\n");
                        goto out;
                }
@@ -1359,7 +1360,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
                goto found;
        /* Don't log an error when called from regulator_get_optional() */
        } else if (!have_full_constraints() || exclusive) {
-               dev_err(dev, "dummy supplies not allowed\n");
+               dev_warn(dev, "dummy supplies not allowed\n");
        }
 
        mutex_unlock(&regulator_list_mutex);
@@ -1907,8 +1908,6 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
 
        trace_regulator_disable_complete(rdev_get_name(rdev));
 
-       _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
-                            NULL);
        return 0;
 }
 
@@ -1932,6 +1931,8 @@ static int _regulator_disable(struct regulator_dev *rdev)
                                rdev_err(rdev, "failed to disable\n");
                                return ret;
                        }
+                       _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+                                       NULL);
                }
 
                rdev->use_count = 0;
@@ -1984,20 +1985,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
 {
        int ret = 0;
 
-       /* force disable */
-       if (rdev->desc->ops->disable) {
-               /* ah well, who wants to live forever... */
-               ret = rdev->desc->ops->disable(rdev);
-               if (ret < 0) {
-                       rdev_err(rdev, "failed to force disable\n");
-                       return ret;
-               }
-               /* notify other consumers that power has been forced off */
-               _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
-                       REGULATOR_EVENT_DISABLE, NULL);
+       ret = _regulator_do_disable(rdev);
+       if (ret < 0) {
+               rdev_err(rdev, "failed to force disable\n");
+               return ret;
        }
 
-       return ret;
+       _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
+                       REGULATOR_EVENT_DISABLE, NULL);
+
+       return 0;
 }
 
 /**
@@ -3630,23 +3627,18 @@ int regulator_suspend_finish(void)
 
        mutex_lock(&regulator_list_mutex);
        list_for_each_entry(rdev, &regulator_list, list) {
-               struct regulator_ops *ops = rdev->desc->ops;
-
                mutex_lock(&rdev->mutex);
-               if ((rdev->use_count > 0  || rdev->constraints->always_on) &&
-                               ops->enable) {
-                       error = ops->enable(rdev);
+               if (rdev->use_count > 0  || rdev->constraints->always_on) {
+                       error = _regulator_do_enable(rdev);
                        if (error)
                                ret = error;
                } else {
                        if (!have_full_constraints())
                                goto unlock;
-                       if (!ops->disable)
-                               goto unlock;
                        if (!_regulator_is_enabled(rdev))
                                goto unlock;
 
-                       error = ops->disable(rdev);
+                       error = _regulator_do_disable(rdev);
                        if (error)
                                ret = error;
                }
@@ -3820,7 +3812,7 @@ static int __init regulator_init_complete(void)
                ops = rdev->desc->ops;
                c = rdev->constraints;
 
-               if (!ops->disable || (c && c->always_on))
+               if (c && c->always_on)
                        continue;
 
                mutex_lock(&rdev->mutex);
@@ -3841,7 +3833,7 @@ static int __init regulator_init_complete(void)
                        /* We log since this may kill the system if it
                         * goes wrong. */
                        rdev_info(rdev, "disabling\n");
-                       ret = ops->disable(rdev);
+                       ret = _regulator_do_disable(rdev);
                        if (ret != 0)
                                rdev_err(rdev, "couldn't disable: %d\n", ret);
                } else {
index 56727eb745df69171d77fac8313e6ea3ab2499ef..91e99a2c8dc14354c4f60368f025fef15d78786e 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * Regulator driver for DA9063 PMIC series
  *
@@ -60,7 +61,8 @@ struct da9063_regulator_info {
        .desc.ops = &da9063_ldo_ops, \
        .desc.min_uV = (min_mV) * 1000, \
        .desc.uV_step = (step_mV) * 1000, \
-       .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1), \
+       .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1 \
+               + (DA9063_V##regl_name##_BIAS)), \
        .desc.enable_reg = DA9063_REG_##regl_name##_CONT, \
        .desc.enable_mask = DA9063_LDO_EN, \
        .desc.vsel_reg = DA9063_REG_V##regl_name##_A, \
index 186df8785a912483ee84050160649eb7911037c2..e0619526708c88393069abf4411fa2ff9473e510 100644 (file)
@@ -166,9 +166,10 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
 
        ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
                        MAX14577_REG_MAX);
-       if (ret < 0) {
+       if (ret < 0)
                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
-       }
+       else
+               ret = 0;
 
        of_node_put(np);
 
index d7164bb75d3e0bf2a88a61c1a82e6c79072cd8b5..d958dfa051254866808fe6c36cf9db7184627b94 100644 (file)
@@ -535,7 +535,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
                return -ENODEV;
        }
 
-       regulators_np = of_find_node_by_name(pmic_np, "regulators");
+       regulators_np = of_get_child_by_name(pmic_np, "regulators");
        if (!regulators_np) {
                dev_err(iodev->dev, "could not find regulators sub-node\n");
                return -EINVAL;
@@ -591,6 +591,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
                rmode++;
        }
 
+       of_node_put(regulators_np);
+
        if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) {
                pdata->buck2_gpiodvs = true;
 
index 7afd373b9595ff68b16238fc37688102dbaa04f4..c4cde9c08f1ffa9ed5c7c1d91a10b745ef7fdb3e 100644 (file)
@@ -580,10 +580,12 @@ static int s3c_rtc_suspend(struct device *dev)
 
        clk_enable(rtc_clk);
        /* save TICNT for anyone using periodic interrupts */
-       ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
        if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
                ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
                ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+               ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT);
+       } else {
+               ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
        }
        s3c_rtc_enable(pdev, 0);
 
@@ -605,10 +607,15 @@ static int s3c_rtc_resume(struct device *dev)
 
        clk_enable(rtc_clk);
        s3c_rtc_enable(pdev, 1);
-       writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
-               tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
-               writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+               writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+               if (ticnt_en_save) {
+                       tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
+                       writew(tmp | ticnt_en_save,
+                                       s3c_rtc_base + S3C2410_RTCCON);
+               }
+       } else {
+               writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
        }
 
        if (device_may_wakeup(dev) && wake_en) {
index f6b9188c5af581b8c0d587932c5de1af5d996951..9f0ea6cb6922619dfe04803c284002431110e11f 100644 (file)
@@ -610,6 +610,7 @@ void chsc_chp_online(struct chp_id chpid)
                css_wait_for_slow_path();
                for_each_subchannel_staged(__s390_process_res_acc, NULL,
                                           &link);
+               css_schedule_reprobe();
        }
 }
 
index dc542e0a3055a6abb63314ee6dd20ecc451c7d2d..0bc91e46395a8d84ad8c989b6d2a7844593c3ba0 100644 (file)
@@ -311,7 +311,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
        } __packed * msg = ap_msg->message;
 
        int rcblen = CEIL4(xcRB->request_control_blk_length);
-       int replylen;
+       int replylen, req_sumlen, resp_sumlen;
        char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
        char *function_code;
 
@@ -321,12 +321,34 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
                xcRB->request_data_length;
        if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE)
                return -EINVAL;
+
+       /* Overflow check
+          sum must be greater (or equal) than the largest operand */
+       req_sumlen = CEIL4(xcRB->request_control_blk_length) +
+                       xcRB->request_data_length;
+       if ((CEIL4(xcRB->request_control_blk_length) <=
+                                               xcRB->request_data_length) ?
+               (req_sumlen < xcRB->request_data_length) :
+               (req_sumlen < CEIL4(xcRB->request_control_blk_length))) {
+               return -EINVAL;
+       }
+
        replylen = sizeof(struct type86_fmt2_msg) +
                CEIL4(xcRB->reply_control_blk_length) +
                xcRB->reply_data_length;
        if (replylen > MSGTYPE06_MAX_MSG_SIZE)
                return -EINVAL;
 
+       /* Overflow check
+          sum must be greater (or equal) than the largest operand */
+       resp_sumlen = CEIL4(xcRB->reply_control_blk_length) +
+                       xcRB->reply_data_length;
+       if ((CEIL4(xcRB->reply_control_blk_length) <= xcRB->reply_data_length) ?
+               (resp_sumlen < xcRB->reply_data_length) :
+               (resp_sumlen < CEIL4(xcRB->reply_control_blk_length))) {
+               return -EINVAL;
+       }
+
        /* prepare type6 header */
        msg->hdr = static_type6_hdrX;
        memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
index c3a83df07894e51195d914111c15be2c615f09c1..795ed61a549632adc16b808622f75c911f66634d 100644 (file)
@@ -1660,7 +1660,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
                                QDIO_FLAG_CLEANUP_USING_CLEAR);
                if (rc)
                        QETH_CARD_TEXT_(card, 3, "1err%d", rc);
-               qdio_free(CARD_DDEV(card));
                atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
                break;
        case QETH_QDIO_CLEANING:
@@ -2605,6 +2604,7 @@ static int qeth_mpc_initialize(struct qeth_card *card)
        return 0;
 out_qdio:
        qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
+       qdio_free(CARD_DDEV(card));
        return rc;
 }
 
@@ -4906,9 +4906,11 @@ retry:
        if (retries < 3)
                QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
                        dev_name(&card->gdev->dev));
+       rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
+       qdio_free(CARD_DDEV(card));
        rc = ccw_device_set_online(CARD_RDEV(card));
        if (rc)
                goto retriable;
@@ -4918,7 +4920,6 @@ retry:
        rc = ccw_device_set_online(CARD_DDEV(card));
        if (rc)
                goto retriable;
-       rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
 retriable:
        if (rc == -ERESTARTSYS) {
                QETH_DBF_TEXT(SETUP, 2, "break1");
index 0710550093ce6ac5fea8ddbf80f8409bbc1186f6..908d82529ee9c3e04a42caf92b9e0787836ef7d0 100644 (file)
@@ -1091,6 +1091,7 @@ out_remove:
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_RECOVER)
                card->state = CARD_STATE_RECOVER;
        else
@@ -1132,6 +1133,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
                rc = (rc2) ? rc2 : rc3;
        if (rc)
                QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_UP)
                card->state = CARD_STATE_RECOVER;
        /* let user_space know that device is offline */
@@ -1194,6 +1196,7 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
                qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
        qeth_qdio_clear_card(card, 0);
        qeth_clear_qdio_buffers(card);
+       qdio_free(CARD_DDEV(card));
 }
 
 static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
index 0f430424c3b8b0aec231c3e2ca69d739c0c29701..3524d34ff694c273afefc7d85bfa17b6bce38af9 100644 (file)
@@ -3447,6 +3447,7 @@ out_remove:
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_RECOVER)
                card->state = CARD_STATE_RECOVER;
        else
@@ -3493,6 +3494,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
                rc = (rc2) ? rc2 : rc3;
        if (rc)
                QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_UP)
                card->state = CARD_STATE_RECOVER;
        /* let user_space know that device is offline */
@@ -3545,6 +3547,7 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
                qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
        qeth_qdio_clear_card(card, 0);
        qeth_clear_qdio_buffers(card);
+       qdio_free(CARD_DDEV(card));
 }
 
 static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
index 6b4678a7900a086e711d4bf9a7f6004bc2efcb3c..4ccb5d869389e353113692d20f02f66d002046cd 100644 (file)
@@ -507,7 +507,6 @@ static int jsflash_init(void)
        }
 
        /* Let us be really paranoid for modifications to probing code. */
-       /* extern enum sparc_cpu sparc_cpu_model; */ /* in <asm/system.h> */
        if (sparc_cpu_model != sun4m) {
                /* We must be on sun4m because we use MMU Bypass ASI. */
                return -ENXIO;
index 2eb97d7e8d122e21f7d3128270846754b4561313..0cb73074c1997409c4e63f6d39ac51e641eff088 100644 (file)
@@ -790,17 +790,32 @@ static inline int test_tgt_sess_count(struct qla_tgt *tgt)
 }
 
 /* Called by tcm_qla2xxx configfs code */
-void qlt_stop_phase1(struct qla_tgt *tgt)
+int qlt_stop_phase1(struct qla_tgt *tgt)
 {
        struct scsi_qla_host *vha = tgt->vha;
        struct qla_hw_data *ha = tgt->ha;
        unsigned long flags;
 
+       mutex_lock(&qla_tgt_mutex);
+       if (!vha->fc_vport) {
+               struct Scsi_Host *sh = vha->host;
+               struct fc_host_attrs *fc_host = shost_to_fc_host(sh);
+               bool npiv_vports;
+
+               spin_lock_irqsave(sh->host_lock, flags);
+               npiv_vports = (fc_host->npiv_vports_inuse);
+               spin_unlock_irqrestore(sh->host_lock, flags);
+
+               if (npiv_vports) {
+                       mutex_unlock(&qla_tgt_mutex);
+                       return -EPERM;
+               }
+       }
        if (tgt->tgt_stop || tgt->tgt_stopped) {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e,
                    "Already in tgt->tgt_stop or tgt_stopped state\n");
-               dump_stack();
-               return;
+               mutex_unlock(&qla_tgt_mutex);
+               return -EPERM;
        }
 
        ql_dbg(ql_dbg_tgt, vha, 0xe003, "Stopping target for host %ld(%p)\n",
@@ -815,6 +830,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
        qlt_clear_tgt_db(tgt, true);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
        mutex_unlock(&vha->vha_tgt.tgt_mutex);
+       mutex_unlock(&qla_tgt_mutex);
 
        flush_delayed_work(&tgt->sess_del_work);
 
@@ -841,6 +857,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
 
        /* Wait for sessions to clear out (just in case) */
        wait_event(tgt->waitQ, test_tgt_sess_count(tgt));
+       return 0;
 }
 EXPORT_SYMBOL(qlt_stop_phase1);
 
@@ -3185,7 +3202,8 @@ restart:
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02c,
                    "SRR cmd %p (se_cmd %p, tag %d, op %x), "
                    "sg_cnt=%d, offset=%d", cmd, &cmd->se_cmd, cmd->tag,
-                   se_cmd->t_task_cdb[0], cmd->sg_cnt, cmd->offset);
+                   se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0,
+                   cmd->sg_cnt, cmd->offset);
 
                qlt_handle_srr(vha, sctio, imm);
 
@@ -4181,6 +4199,9 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha)
        tgt->datasegs_per_cmd = QLA_TGT_DATASEGS_PER_CMD_24XX;
        tgt->datasegs_per_cont = QLA_TGT_DATASEGS_PER_CONT_24XX;
 
+       if (base_vha->fc_vport)
+               return 0;
+
        mutex_lock(&qla_tgt_mutex);
        list_add_tail(&tgt->tgt_list_entry, &qla_tgt_glist);
        mutex_unlock(&qla_tgt_mutex);
@@ -4194,6 +4215,10 @@ int qlt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha)
        if (!vha->vha_tgt.qla_tgt)
                return 0;
 
+       if (vha->fc_vport) {
+               qlt_release(vha->vha_tgt.qla_tgt);
+               return 0;
+       }
        mutex_lock(&qla_tgt_mutex);
        list_del(&vha->vha_tgt.qla_tgt->tgt_list_entry);
        mutex_unlock(&qla_tgt_mutex);
@@ -4265,6 +4290,12 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
                        continue;
                }
+               if (tgt->tgt_stop) {
+                       pr_debug("MODE_TARGET in shutdown on qla2xxx(%d)\n",
+                                host->host_no);
+                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+                       continue;
+               }
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
                if (!scsi_host_get(host)) {
@@ -4279,12 +4310,11 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
                        scsi_host_put(host);
                        continue;
                }
-               mutex_unlock(&qla_tgt_mutex);
-
                rc = (*callback)(vha, target_lport_ptr, npiv_wwpn, npiv_wwnn);
                if (rc != 0)
                        scsi_host_put(host);
 
+               mutex_unlock(&qla_tgt_mutex);
                return rc;
        }
        mutex_unlock(&qla_tgt_mutex);
index 66e755cdde573c47e902b1f45e0ac65b18d772bd..ce33d8c26406da00ccb67943093bae5f3fdec0b9 100644 (file)
@@ -1001,7 +1001,7 @@ extern void qlt_modify_vp_config(struct scsi_qla_host *,
 extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *);
 extern int qlt_mem_alloc(struct qla_hw_data *);
 extern void qlt_mem_free(struct qla_hw_data *);
-extern void qlt_stop_phase1(struct qla_tgt *);
+extern int qlt_stop_phase1(struct qla_tgt *);
 extern void qlt_stop_phase2(struct qla_tgt *);
 extern irqreturn_t qla83xx_msix_atio_q(int, void *);
 extern void qlt_83xx_iospace_config(struct qla_hw_data *);
index 75a141bbe74d178834a9f58c6fc723734e63758f..788c4fe2b0c9ec7a8113078c318421d7407ae855 100644 (file)
@@ -182,20 +182,6 @@ static int tcm_qla2xxx_npiv_parse_wwn(
        return 0;
 }
 
-static ssize_t tcm_qla2xxx_npiv_format_wwn(char *buf, size_t len,
-                                       u64 wwpn, u64 wwnn)
-{
-       u8 b[8], b2[8];
-
-       put_unaligned_be64(wwpn, b);
-       put_unaligned_be64(wwnn, b2);
-       return snprintf(buf, len,
-               "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x,"
-               "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
-               b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
-               b2[0], b2[1], b2[2], b2[3], b2[4], b2[5], b2[6], b2[7]);
-}
-
 static char *tcm_qla2xxx_npiv_get_fabric_name(void)
 {
        return "qla2xxx_npiv";
@@ -227,15 +213,6 @@ static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg)
        return lport->lport_naa_name;
 }
 
-static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
-       struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
-                               struct tcm_qla2xxx_tpg, se_tpg);
-       struct tcm_qla2xxx_lport *lport = tpg->lport;
-
-       return &lport->lport_npiv_name[0];
-}
-
 static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg)
 {
        struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
@@ -941,15 +918,41 @@ static ssize_t tcm_qla2xxx_tpg_show_enable(
                        atomic_read(&tpg->lport_tpg_enabled));
 }
 
+static void tcm_qla2xxx_depend_tpg(struct work_struct *work)
+{
+       struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+                               struct tcm_qla2xxx_tpg, tpg_base_work);
+       struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+       struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+       if (!configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
+                                 &se_tpg->tpg_group.cg_item)) {
+               atomic_set(&base_tpg->lport_tpg_enabled, 1);
+               qlt_enable_vha(base_vha);
+       }
+       complete(&base_tpg->tpg_base_comp);
+}
+
+static void tcm_qla2xxx_undepend_tpg(struct work_struct *work)
+{
+       struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+                               struct tcm_qla2xxx_tpg, tpg_base_work);
+       struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+       struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+       if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) {
+               atomic_set(&base_tpg->lport_tpg_enabled, 0);
+               configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
+                                      &se_tpg->tpg_group.cg_item);
+       }
+       complete(&base_tpg->tpg_base_comp);
+}
+
 static ssize_t tcm_qla2xxx_tpg_store_enable(
        struct se_portal_group *se_tpg,
        const char *page,
        size_t count)
 {
-       struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
-       struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
-                       struct tcm_qla2xxx_lport, lport_wwn);
-       struct scsi_qla_host *vha = lport->qla_vha;
        struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
                        struct tcm_qla2xxx_tpg, se_tpg);
        unsigned long op;
@@ -964,19 +967,28 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
                pr_err("Illegal value for tpg_enable: %lu\n", op);
                return -EINVAL;
        }
-
        if (op) {
-               atomic_set(&tpg->lport_tpg_enabled, 1);
-               qlt_enable_vha(vha);
+               if (atomic_read(&tpg->lport_tpg_enabled))
+                       return -EEXIST;
+
+               INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_depend_tpg);
        } else {
-               if (!vha->vha_tgt.qla_tgt) {
-                       pr_err("struct qla_hw_data *vha->vha_tgt.qla_tgt is NULL\n");
-                       return -ENODEV;
-               }
-               atomic_set(&tpg->lport_tpg_enabled, 0);
-               qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+               if (!atomic_read(&tpg->lport_tpg_enabled))
+                       return count;
+
+               INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_undepend_tpg);
        }
+       init_completion(&tpg->tpg_base_comp);
+       schedule_work(&tpg->tpg_base_work);
+       wait_for_completion(&tpg->tpg_base_comp);
 
+       if (op) {
+               if (!atomic_read(&tpg->lport_tpg_enabled))
+                       return -ENODEV;
+       } else {
+               if (atomic_read(&tpg->lport_tpg_enabled))
+                       return -EPERM;
+       }
        return count;
 }
 
@@ -1053,11 +1065,64 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg)
        /*
         * Clear local TPG=1 pointer for non NPIV mode.
         */
-               lport->tpg_1 = NULL;
-
+       lport->tpg_1 = NULL;
        kfree(tpg);
 }
 
+static ssize_t tcm_qla2xxx_npiv_tpg_show_enable(
+       struct se_portal_group *se_tpg,
+       char *page)
+{
+       return tcm_qla2xxx_tpg_show_enable(se_tpg, page);
+}
+
+static ssize_t tcm_qla2xxx_npiv_tpg_store_enable(
+       struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
+       struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
+                       struct tcm_qla2xxx_lport, lport_wwn);
+       struct scsi_qla_host *vha = lport->qla_vha;
+       struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
+                       struct tcm_qla2xxx_tpg, se_tpg);
+       unsigned long op;
+       int rc;
+
+       rc = kstrtoul(page, 0, &op);
+       if (rc < 0) {
+               pr_err("kstrtoul() returned %d\n", rc);
+               return -EINVAL;
+       }
+       if ((op != 1) && (op != 0)) {
+               pr_err("Illegal value for tpg_enable: %lu\n", op);
+               return -EINVAL;
+       }
+       if (op) {
+               if (atomic_read(&tpg->lport_tpg_enabled))
+                       return -EEXIST;
+
+               atomic_set(&tpg->lport_tpg_enabled, 1);
+               qlt_enable_vha(vha);
+       } else {
+               if (!atomic_read(&tpg->lport_tpg_enabled))
+                       return count;
+
+               atomic_set(&tpg->lport_tpg_enabled, 0);
+               qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+       }
+
+       return count;
+}
+
+TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = {
+        &tcm_qla2xxx_npiv_tpg_enable.attr,
+        NULL,
+};
+
 static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
        struct se_wwn *wwn,
        struct config_group *group,
@@ -1650,6 +1715,9 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
        struct scsi_qla_host *npiv_vha;
        struct tcm_qla2xxx_lport *lport =
                        (struct tcm_qla2xxx_lport *)target_lport_ptr;
+       struct tcm_qla2xxx_lport *base_lport =
+                       (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr;
+       struct tcm_qla2xxx_tpg *base_tpg;
        struct fc_vport_identifiers vport_id;
 
        if (!qla_tgt_mode_enabled(base_vha)) {
@@ -1657,6 +1725,13 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
                return -EPERM;
        }
 
+       if (!base_lport || !base_lport->tpg_1 ||
+           !atomic_read(&base_lport->tpg_1->lport_tpg_enabled)) {
+               pr_err("qla2xxx base_lport or tpg_1 not available\n");
+               return -EPERM;
+       }
+       base_tpg = base_lport->tpg_1;
+
        memset(&vport_id, 0, sizeof(vport_id));
        vport_id.port_name = npiv_wwpn;
        vport_id.node_name = npiv_wwnn;
@@ -1675,7 +1750,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
        npiv_vha = (struct scsi_qla_host *)vport->dd_data;
        npiv_vha->vha_tgt.target_lport_ptr = target_lport_ptr;
        lport->qla_vha = npiv_vha;
-
        scsi_host_get(npiv_vha->host);
        return 0;
 }
@@ -1714,8 +1788,6 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
        }
        lport->lport_npiv_wwpn = npiv_wwpn;
        lport->lport_npiv_wwnn = npiv_wwnn;
-       tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0],
-                       TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn);
        sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn);
 
        ret = tcm_qla2xxx_init_lport(lport);
@@ -1824,7 +1896,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
 static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
        .get_fabric_name                = tcm_qla2xxx_npiv_get_fabric_name,
        .get_fabric_proto_ident         = tcm_qla2xxx_get_fabric_proto_ident,
-       .tpg_get_wwn                    = tcm_qla2xxx_npiv_get_fabric_wwn,
+       .tpg_get_wwn                    = tcm_qla2xxx_get_fabric_wwn,
        .tpg_get_tag                    = tcm_qla2xxx_get_tag,
        .tpg_get_default_depth          = tcm_qla2xxx_get_default_depth,
        .tpg_get_pr_transport_id        = tcm_qla2xxx_get_pr_transport_id,
@@ -1935,7 +2007,7 @@ static int tcm_qla2xxx_register_configfs(void)
         */
        npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs =
-           tcm_qla2xxx_tpg_attrs;
+           tcm_qla2xxx_npiv_tpg_attrs;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
index 275d8b9a7a34121d4d7d356659bfe92816219a3f..33aaac8c7d5936bbdd3e2d9f934f2c92f2083331 100644 (file)
@@ -4,8 +4,6 @@
 #define TCM_QLA2XXX_VERSION    "v0.1"
 /* length of ASCII WWPNs including pad */
 #define TCM_QLA2XXX_NAMELEN    32
-/* lenth of ASCII NPIV 'WWPN+WWNN' including pad */
-#define TCM_QLA2XXX_NPIV_NAMELEN 66
 
 #include "qla_target.h"
 
@@ -43,6 +41,9 @@ struct tcm_qla2xxx_tpg {
        struct tcm_qla2xxx_tpg_attrib tpg_attrib;
        /* Returned by tcm_qla2xxx_make_tpg() */
        struct se_portal_group se_tpg;
+       /* Items for dealing with configfs_depend_item */
+       struct completion tpg_base_comp;
+       struct work_struct tpg_base_work;
 };
 
 struct tcm_qla2xxx_fc_loopid {
@@ -62,8 +63,6 @@ struct tcm_qla2xxx_lport {
        char lport_name[TCM_QLA2XXX_NAMELEN];
        /* ASCII formatted naa WWPN for VPD page 83 etc */
        char lport_naa_name[TCM_QLA2XXX_NAMELEN];
-       /* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */
-       char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN];
        /* map for fc_port pointers in 24-bit FC Port ID space */
        struct btree_head32 lport_fcport_map;
        /* vmalloc-ed memory for fc_port pointers for 16-bit FC loop ID */
index 31534b51715aa95e29664cc80d44d71b5131d0ab..c3b2fb9b6713c997b1338d5df13470e0227a5d93 100644 (file)
@@ -132,9 +132,9 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
 
                flags = GPIOF_DIR_OUT;
                if (spi->mode & SPI_CS_HIGH)
-                       flags |= GPIOF_INIT_HIGH;
-               else
                        flags |= GPIOF_INIT_LOW;
+               else
+                       flags |= GPIOF_INIT_HIGH;
 
                status = gpio_request_one(cdata->gpio, flags,
                                          dev_name(&spi->dev));
index b0842f75101647616ada3a3db4f545a57b519be0..5d7b07f083266e64ab0d91436c10ae89a9ec112c 100644 (file)
@@ -1455,6 +1455,14 @@ static int atmel_spi_suspend(struct device *dev)
 {
        struct spi_master       *master = dev_get_drvdata(dev);
        struct atmel_spi        *as = spi_master_get_devdata(master);
+       int ret;
+
+       /* Stop the queue running */
+       ret = spi_master_suspend(master);
+       if (ret) {
+               dev_warn(dev, "cannot suspend master\n");
+               return ret;
+       }
 
        clk_disable_unprepare(as->clk);
        return 0;
@@ -1464,9 +1472,16 @@ static int atmel_spi_resume(struct device *dev)
 {
        struct spi_master       *master = dev_get_drvdata(dev);
        struct atmel_spi        *as = spi_master_get_devdata(master);
+       int ret;
 
        clk_prepare_enable(as->clk);
-       return 0;
+
+       /* Start the queue running */
+       ret = spi_master_resume(master);
+       if (ret)
+               dev_err(dev, "problem starting queue (%d)\n", ret);
+
+       return ret;
 }
 
 static SIMPLE_DEV_PM_OPS(atmel_spi_pm_ops, atmel_spi_suspend, atmel_spi_resume);
index cabed8f9119e1af30d80766420d548b94567c91c..28ae470397a9e0a7c77c88f5370327e73df01a67 100644 (file)
@@ -514,7 +514,8 @@ static int mcfqspi_resume(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int mcfqspi_runtime_suspend(struct device *dev)
 {
-       struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
 
        clk_disable(mcfqspi->clk);
 
@@ -523,7 +524,8 @@ static int mcfqspi_runtime_suspend(struct device *dev)
 
 static int mcfqspi_runtime_resume(struct device *dev)
 {
-       struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
 
        clk_enable(mcfqspi->clk);
 
index ec79f726672a14f7644810101afe59e82322976c..a25392065d9b838ef852e93d09e53d0d121ac485 100644 (file)
@@ -420,7 +420,6 @@ static int dspi_suspend(struct device *dev)
 
 static int dspi_resume(struct device *dev)
 {
-
        struct spi_master *master = dev_get_drvdata(dev);
        struct fsl_dspi *dspi = spi_master_get_devdata(master);
 
@@ -504,7 +503,7 @@ static int dspi_probe(struct platform_device *pdev)
        clk_prepare_enable(dspi->clk);
 
        init_waitqueue_head(&dspi->waitq);
-       platform_set_drvdata(pdev, dspi);
+       platform_set_drvdata(pdev, master);
 
        ret = spi_bitbang_start(&dspi->bitbang);
        if (ret != 0) {
@@ -525,7 +524,8 @@ out_master_put:
 
 static int dspi_remove(struct platform_device *pdev)
 {
-       struct fsl_dspi *dspi = platform_get_drvdata(pdev);
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct fsl_dspi *dspi = spi_master_get_devdata(master);
 
        /* Disconnect from the SPI framework */
        spi_bitbang_stop(&dspi->bitbang);
index a5474ef9d2a0cf4ad7367ee1e0399fae2e982145..47f15d97e7fa41efeede0bce941d4584a0c07be5 100644 (file)
@@ -948,8 +948,8 @@ static int spi_imx_remove(struct platform_device *pdev)
        spi_bitbang_stop(&spi_imx->bitbang);
 
        writel(0, spi_imx->base + MXC_CSPICTRL);
-       clk_disable_unprepare(spi_imx->clk_ipg);
-       clk_disable_unprepare(spi_imx->clk_per);
+       clk_unprepare(spi_imx->clk_ipg);
+       clk_unprepare(spi_imx->clk_per);
        spi_master_put(master);
 
        return 0;
index 2e7f38c7a9610b11f63fd36c816f311b3372d66d..88eb57e858b379ac258abad703bf532b60852669 100644 (file)
@@ -915,7 +915,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
        /* Set Tx DMA */
        param = &dma->param_tx;
        param->dma_dev = &dma_dev->dev;
-       param->chan_id = data->master->bus_num * 2; /* Tx = 0, 2 */
+       param->chan_id = data->ch * 2; /* Tx = 0, 2 */;
        param->tx_reg = data->io_base_addr + PCH_SPDWR;
        param->width = width;
        chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -930,7 +930,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
        /* Set Rx DMA */
        param = &dma->param_rx;
        param->dma_dev = &dma_dev->dev;
-       param->chan_id = data->master->bus_num * 2 + 1; /* Rx = Tx + 1 */
+       param->chan_id = data->ch * 2 + 1; /* Rx = Tx + 1 */;
        param->rx_reg = data->io_base_addr + PCH_SPDRR;
        param->width = width;
        chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -1452,6 +1452,11 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
 
        pch_spi_set_master_mode(master);
 
+       if (use_dma) {
+               dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
+               pch_alloc_dma_buf(board_dat, data);
+       }
+
        ret = spi_register_master(master);
        if (ret != 0) {
                dev_err(&plat_dev->dev,
@@ -1459,14 +1464,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
                goto err_spi_register_master;
        }
 
-       if (use_dma) {
-               dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
-               pch_alloc_dma_buf(board_dat, data);
-       }
-
        return 0;
 
 err_spi_register_master:
+       pch_free_dma_buf(board_dat, data);
        free_irq(board_dat->pdev->irq, data);
 err_request_irq:
        pch_spi_free_resources(board_dat, data);
index eaec1dab7fe489fbbc9d171a4acdf5f78d765df6..1432d956769c2d5511716a5e8d3ea1eb5a667b68 100644 (file)
@@ -2904,7 +2904,7 @@ static int binder_node_release(struct binder_node *node, int refs)
                refs++;
 
                if (!ref->death)
-                       goto out;
+                       continue;
 
                death++;
 
@@ -2917,7 +2917,6 @@ static int binder_node_release(struct binder_node *node, int refs)
                        BUG();
        }
 
-out:
        binder_debug(BINDER_DEBUG_DEAD_BINDER,
                     "node %d now dead, refs %d, death %d\n",
                     node->debug_id, refs, death);
index 4a08e16e42f719470cd9a0b63de557d2b3ff704b..79206cb3fb946e785021607c7b12474bff9d73a5 100644 (file)
@@ -866,6 +866,8 @@ c4_ioctl (struct net_device *ndev, struct ifreq *ifr, int cmd)
             _IOC_SIZE (iocmd));
 #endif
     iolen = _IOC_SIZE (iocmd);
+    if (iolen > sizeof(arg))
+        return -EFAULT;
     data = ifr->ifr_data + sizeof (iocmd);
     if (copy_from_user (&arg, data, iolen))
         return -EFAULT;
index 7fc66a6a6e36c19077144c702b32e91bb1767792..514844efac75833252f25891d591dad1d844092c 100644 (file)
@@ -757,6 +757,7 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid)
        }
 
        /* if it is released, wait for the next touch via IRQ */
+       lradc->cur_plate = LRADC_TOUCH;
        mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1);
        mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
 }
index a70dcef1419e9d9541b0414c9a3da8bf7380ca61..2f40ff5901d64706e82e2f120208c62ef5b291f8 100644 (file)
@@ -55,6 +55,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = {
        /****** 8188EUS ********/
        {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */
        {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
+       {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
        {}      /* Terminating entry */
 };
 
index 75ae4387fe19ff8f34cb828118dba6bab5cae1a4..963b55f661c8d370a05c09be7bbfca2e394c369e 100644 (file)
@@ -616,7 +616,7 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
                                return false;
                }
 
-               if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+               if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
                        (ieee80211_has_protected(hdr->frame_control)))
                        rx_status->flag &= ~RX_FLAG_DECRYPTED;
                else
index a7d24c95191d15826ac808b226c26ae71e12ac98..7dd2b95416e87975f01670ba955865e89390c0b2 100644 (file)
@@ -416,7 +416,7 @@ static int prism2_scan(struct wiphy *wiphy,
                memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len);
                bss = cfg80211_inform_bss(wiphy,
                        ieee80211_get_channel(wiphy,
-                             ieee80211_dsss_chan_to_freq(msg2.dschannel.data)),
+                             ieee80211_channel_to_frequency(msg2.dschannel.data, IEEE80211_BAND_2GHZ)),
                        (const u8 *) &(msg2.bssid.data.data),
                        msg2.timestamp.data, msg2.capinfo.data,
                        msg2.beaconperiod.data,
index 7f1a7ce4b771a791cdf636906fd5fcdcc16c9ba6..b83ec378d04f8f1ed5fbc820429c6f1657b4d7a0 100644 (file)
@@ -785,7 +785,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
        spin_unlock_bh(&conn->cmd_lock);
 
        list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) {
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                iscsit_free_cmd(cmd, false);
        }
 }
@@ -3708,7 +3708,7 @@ iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state
                break;
        case ISTATE_REMOVE:
                spin_lock_bh(&conn->cmd_lock);
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_free_cmd(cmd, false);
@@ -4151,7 +4151,7 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
        spin_lock_bh(&conn->cmd_lock);
        list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
 
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_increment_maxcmdsn(cmd, sess);
@@ -4196,6 +4196,10 @@ int iscsit_close_connection(
        iscsit_stop_timers_for_cmds(conn);
        iscsit_stop_nopin_response_timer(conn);
        iscsit_stop_nopin_timer(conn);
+
+       if (conn->conn_transport->iscsit_wait_conn)
+               conn->conn_transport->iscsit_wait_conn(conn);
+
        iscsit_free_queue_reqs_for_conn(conn);
 
        /*
index 33be1fb1df32f2850b6ceb1d54b3b5340a2b6bb1..4ca8fd2a70db4c05597f6b4bfbac171ce58ea8c7 100644 (file)
@@ -138,7 +138,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
                list_for_each_entry_safe(cmd, cmd_tmp,
                                &cr->conn_recovery_cmd_list, i_conn_node) {
 
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        cmd->conn = NULL;
                        spin_unlock(&cr->conn_recovery_cmd_lock);
                        iscsit_free_cmd(cmd, true);
@@ -160,7 +160,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
                list_for_each_entry_safe(cmd, cmd_tmp,
                                &cr->conn_recovery_cmd_list, i_conn_node) {
 
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        cmd->conn = NULL;
                        spin_unlock(&cr->conn_recovery_cmd_lock);
                        iscsit_free_cmd(cmd, true);
@@ -216,7 +216,7 @@ int iscsit_remove_cmd_from_connection_recovery(
        }
        cr = cmd->cr;
 
-       list_del(&cmd->i_conn_node);
+       list_del_init(&cmd->i_conn_node);
        return --cr->cmd_count;
 }
 
@@ -297,7 +297,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
                if (!(cmd->cmd_flags & ICF_OOO_CMDSN))
                        continue;
 
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
 
                spin_unlock_bh(&conn->cmd_lock);
                iscsit_free_cmd(cmd, true);
@@ -335,7 +335,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
        /*
         * Only perform connection recovery on ISCSI_OP_SCSI_CMD or
         * ISCSI_OP_NOOP_OUT opcodes.  For all other opcodes call
-        * list_del(&cmd->i_conn_node); to release the command to the
+        * list_del_init(&cmd->i_conn_node); to release the command to the
         * session pool and remove it from the connection's list.
         *
         * Also stop the DataOUT timer, which will be restarted after
@@ -351,7 +351,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
                                " CID: %hu\n", cmd->iscsi_opcode,
                                cmd->init_task_tag, cmd->cmd_sn, conn->cid);
 
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        spin_unlock_bh(&conn->cmd_lock);
                        iscsit_free_cmd(cmd, true);
                        spin_lock_bh(&conn->cmd_lock);
@@ -371,7 +371,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
                 */
                if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd &&
                     iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) {
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        spin_unlock_bh(&conn->cmd_lock);
                        iscsit_free_cmd(cmd, true);
                        spin_lock_bh(&conn->cmd_lock);
@@ -393,7 +393,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
 
                cmd->sess = conn->sess;
 
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_free_all_datain_reqs(cmd);
index 39761837608d3a2ff059356e1049779580182952..44a5471de00ffe95c5fccdf5462931efa0acc361 100644 (file)
@@ -137,7 +137,7 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np(
        list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) {
 
                spin_lock(&tpg->tpg_state_lock);
-               if (tpg->tpg_state == TPG_STATE_FREE) {
+               if (tpg->tpg_state != TPG_STATE_ACTIVE) {
                        spin_unlock(&tpg->tpg_state_lock);
                        continue;
                }
index a4489444ffbc640d940869ca7de305b2ae6c4b58..77e6531fb0a1c0a25ed16b71d1936ec37c2ed50a 100644 (file)
@@ -1074,31 +1074,36 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read,
        struct scatterlist *psg;
        void *paddr, *addr;
        unsigned int i, len, left;
-       unsigned int offset = 0;
+       unsigned int offset = sg_off;
 
        left = sectors * dev->prot_length;
 
        for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) {
-
-               len = min(psg->length, left);
-               if (offset >= sg->length) {
-                       sg = sg_next(sg);
-                       offset = 0;
-                       sg_off = sg->offset;
-               }
+               unsigned int psg_len, copied = 0;
 
                paddr = kmap_atomic(sg_page(psg)) + psg->offset;
-               addr = kmap_atomic(sg_page(sg)) + sg_off;
+               psg_len = min(left, psg->length);
+               while (psg_len) {
+                       len = min(psg_len, sg->length - offset);
+                       addr = kmap_atomic(sg_page(sg)) + sg->offset + offset;
 
-               if (read)
-                       memcpy(paddr, addr, len);
-               else
-                       memcpy(addr, paddr, len);
+                       if (read)
+                               memcpy(paddr + copied, addr, len);
+                       else
+                               memcpy(addr, paddr + copied, len);
 
-               left -= len;
-               offset += len;
+                       left -= len;
+                       offset += len;
+                       copied += len;
+                       psg_len -= len;
+
+                       if (offset >= sg->length) {
+                               sg = sg_next(sg);
+                               offset = 0;
+                       }
+                       kunmap_atomic(addr);
+               }
                kunmap_atomic(paddr);
-               kunmap_atomic(addr);
        }
 }
 
@@ -1163,7 +1168,7 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
 {
        struct se_device *dev = cmd->se_dev;
        struct se_dif_v1_tuple *sdt;
-       struct scatterlist *dsg;
+       struct scatterlist *dsg, *psg = sg;
        sector_t sector = start;
        void *daddr, *paddr;
        int i, j, offset = sg_off;
@@ -1171,14 +1176,14 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
 
        for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) {
                daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
-               paddr = kmap_atomic(sg_page(sg)) + sg->offset;
+               paddr = kmap_atomic(sg_page(psg)) + sg->offset;
 
                for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) {
 
-                       if (offset >= sg->length) {
+                       if (offset >= psg->length) {
                                kunmap_atomic(paddr);
-                               sg = sg_next(sg);
-                               paddr = kmap_atomic(sg_page(sg)) + sg->offset;
+                               psg = sg_next(psg);
+                               paddr = kmap_atomic(sg_page(psg)) + psg->offset;
                                offset = 0;
                        }
 
index 24b4f65d8777bd357efbb85f7324ac4d803da101..2956250b7225c99d77a7475b27d1bf881231539f 100644 (file)
@@ -1601,6 +1601,9 @@ void transport_generic_request_failure(struct se_cmd *cmd,
        case TCM_CHECK_CONDITION_ABORT_CMD:
        case TCM_CHECK_CONDITION_UNIT_ATTENTION:
        case TCM_CHECK_CONDITION_NOT_READY:
+       case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
+       case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
+       case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
                break;
        case TCM_OUT_OF_RESOURCES:
                sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
index 35c066489a19ecd1def35f044e45dc52d55688a1..5f88d767671e956fa400b039f2cc21de9bc58621 100644 (file)
@@ -136,6 +136,7 @@ config SPEAR_THERMAL
 config RCAR_THERMAL
        tristate "Renesas R-Car thermal driver"
        depends on ARCH_SHMOBILE || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enable this to plug the R-Car thermal sensor driver into the Linux
          thermal framework.
@@ -210,8 +211,16 @@ config ACPI_INT3403_THERMAL
        tristate "ACPI INT3403 thermal driver"
        depends on X86 && ACPI
        help
-         This driver uses ACPI INT3403 device objects. If present, it will
-         register each INT3403 thermal sensor as a thermal zone.
+         Newer laptops and tablets that use ACPI may have thermal sensors
+         outside the core CPU/SOC for thermal safety reasons. These
+         temperature sensors are also exposed for the OS to use via the so
+         called INT3403 ACPI object. This driver will, on devices that have
+         such sensors, expose the temperature information from these sensors
+         to userspace via the normal thermal framework. This means that a wide
+         range of applications and GUI widgets can show this information to
+         the user or use this information for making decisions. For example,
+         the Intel Thermal Daemon can use this information to allow the user
+         to select his laptop to run without turning on the fans.
 
 menu "Texas Instruments thermal drivers"
 source "drivers/thermal/ti-soc-thermal/Kconfig"
index 338a88bf6662d1fd0b963f0f8bc7c02dce55e73b..71b0ec0c370d73aad18d685118c197735c5b2833 100644 (file)
@@ -56,10 +56,15 @@ static LIST_HEAD(thermal_governor_list);
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
+static struct thermal_governor *def_governor;
+
 static struct thermal_governor *__find_governor(const char *name)
 {
        struct thermal_governor *pos;
 
+       if (!name || !name[0])
+               return def_governor;
+
        list_for_each_entry(pos, &thermal_governor_list, governor_list)
                if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
                        return pos;
@@ -82,17 +87,23 @@ int thermal_register_governor(struct thermal_governor *governor)
        if (__find_governor(governor->name) == NULL) {
                err = 0;
                list_add(&governor->governor_list, &thermal_governor_list);
+               if (!def_governor && !strncmp(governor->name,
+                       DEFAULT_THERMAL_GOVERNOR, THERMAL_NAME_LENGTH))
+                       def_governor = governor;
        }
 
        mutex_lock(&thermal_list_lock);
 
        list_for_each_entry(pos, &thermal_tz_list, node) {
+               /*
+                * only thermal zones with specified tz->tzp->governor_name
+                * may run with tz->govenor unset
+                */
                if (pos->governor)
                        continue;
-               if (pos->tzp)
-                       name = pos->tzp->governor_name;
-               else
-                       name = DEFAULT_THERMAL_GOVERNOR;
+
+               name = pos->tzp->governor_name;
+
                if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
                        pos->governor = governor;
        }
@@ -342,8 +353,8 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
 static void handle_non_critical_trips(struct thermal_zone_device *tz,
                        int trip, enum thermal_trip_type trip_type)
 {
-       if (tz->governor)
-               tz->governor->throttle(tz, trip);
+       tz->governor ? tz->governor->throttle(tz, trip) :
+                      def_governor->throttle(tz, trip);
 }
 
 static void handle_critical_trips(struct thermal_zone_device *tz,
@@ -1107,7 +1118,7 @@ __thermal_cooling_device_register(struct device_node *np,
        INIT_LIST_HEAD(&cdev->thermal_instances);
        cdev->np = np;
        cdev->ops = ops;
-       cdev->updated = true;
+       cdev->updated = false;
        cdev->device.class = &thermal_class;
        cdev->devdata = devdata;
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
@@ -1533,7 +1544,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
        if (tz->tzp)
                tz->governor = __find_governor(tz->tzp->governor_name);
        else
-               tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
+               tz->governor = def_governor;
 
        mutex_unlock(&thermal_governor_lock);
 
index 972e1c73722a4c4ec90cd75af32ce99da6438745..081fd7e6a9f070c683deaea799437a2e459b94f4 100644 (file)
@@ -68,6 +68,10 @@ struct phy_dev_entry {
        struct thermal_zone_device *tzone;
 };
 
+static const struct thermal_zone_params pkg_temp_tz_params = {
+       .no_hwmon       = true,
+};
+
 /* List maintaining number of package instances */
 static LIST_HEAD(phy_dev_list);
 static DEFINE_MUTEX(phy_dev_list_mutex);
@@ -394,7 +398,6 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
        int err;
        u32 tj_max;
        struct phy_dev_entry *phy_dev_entry;
-       char buffer[30];
        int thres_count;
        u32 eax, ebx, ecx, edx;
        u8 *temp;
@@ -440,13 +443,11 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
        phy_dev_entry->first_cpu = cpu;
        phy_dev_entry->tj_max = tj_max;
        phy_dev_entry->ref_cnt = 1;
-       snprintf(buffer, sizeof(buffer), "pkg-temp-%d\n",
-                                       phy_dev_entry->phys_proc_id);
-       phy_dev_entry->tzone = thermal_zone_device_register(buffer,
+       phy_dev_entry->tzone = thermal_zone_device_register("x86_pkg_temp",
                        thres_count,
                        (thres_count == MAX_NUMBER_OF_TRIPS) ?
                                0x03 : 0x01,
-                       phy_dev_entry, &tzone_ops, NULL, 0, 0);
+                       phy_dev_entry, &tzone_ops, &pkg_temp_tz_params, 0, 0);
        if (IS_ERR(phy_dev_entry->tzone)) {
                err = PTR_ERR(phy_dev_entry->tzone);
                goto err_ret_free;
index bd2715a9d8e5ac959ec1681fd920e953859856a3..c74a00ad7add80254ddf98dbaf88ed0725a540e0 100644 (file)
@@ -1267,17 +1267,16 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
  *     @p: output buffer of at least 7 bytes
  *
  *     Generate a name from a driver reference and write it to the output
- *     buffer. Return the number of bytes written.
+ *     buffer.
  *
  *     Locking: None
  */
-static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)
+static void tty_line_name(struct tty_driver *driver, int index, char *p)
 {
        if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)
-               return sprintf(p, "%s", driver->name);
+               strcpy(p, driver->name);
        else
-               return sprintf(p, "%s%d", driver->name,
-                              index + driver->name_base);
+               sprintf(p, "%s%d", driver->name, index + driver->name_base);
 }
 
 /**
@@ -3546,19 +3545,9 @@ static ssize_t show_cons_active(struct device *dev,
                if (i >= ARRAY_SIZE(cs))
                        break;
        }
-       while (i--) {
-               struct tty_driver *driver;
-               const char *name = cs[i]->name;
-               int index = cs[i]->index;
-
-               driver = cs[i]->device(cs[i], &index);
-               if (driver) {
-                       count += tty_line_name(driver, index, buf + count);
-                       count += sprintf(buf + count, "%c", i ? ' ':'\n');
-               } else
-                       count += sprintf(buf + count, "%s%d%c",
-                                        name, index, i ? ' ':'\n');
-       }
+       while (i--)
+               count += sprintf(buf + count, "%s%d%c",
+                                cs[i]->name, cs[i]->index, i ? ' ':'\n');
        console_unlock();
 
        return count;
index 80de2f88ed2c7852fdd38bec785e6d5681cbe310..4ab2cb62dfce4c1b3dfe140ef83f20d4633b9ff0 100644 (file)
@@ -105,7 +105,7 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir)
 
        do {
                /* flush any pending transfer */
-               hw_write(ci, OP_ENDPTFLUSH, BIT(n), BIT(n));
+               hw_write(ci, OP_ENDPTFLUSH, ~0, BIT(n));
                while (hw_read(ci, OP_ENDPTFLUSH, BIT(n)))
                        cpu_relax();
        } while (hw_read(ci, OP_ENDPTSTAT, BIT(n)));
@@ -205,7 +205,7 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl)
        if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num)))
                return -EAGAIN;
 
-       hw_write(ci, OP_ENDPTPRIME, BIT(n), BIT(n));
+       hw_write(ci, OP_ENDPTPRIME, ~0, BIT(n));
 
        while (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
                cpu_relax();
index 8d72f0c659377371cc6c481e33458c7d555f3493..062967c90b2a06e66a081f81ab53aabe1a9e37e4 100644 (file)
@@ -717,6 +717,10 @@ int usb_get_configuration(struct usb_device *dev)
                        result = -ENOMEM;
                        goto err;
                }
+
+               if (dev->quirks & USB_QUIRK_DELAY_INIT)
+                       msleep(100);
+
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
                    bigbuffer, length);
                if (result < 0) {
index 8f37063c0a49eeff7ba2d0902621aaa91800c058..739ee8e8bdfdaf7bc6be98d716255e4f561cc17a 100644 (file)
@@ -47,6 +47,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Microsoft LifeCam-VX700 v2.0 */
        { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* Logitech HD Pro Webcams C920 and C930e */
+       { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT },
+       { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },
+
        /* Logitech Quickcam Fusion */
        { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
 
index 888fbb43b338ecebcaf7cf8cb267fb2de35cc240..e969eb809a853dbb38093a0f5d3d39f57f931bb7 100644 (file)
@@ -360,24 +360,30 @@ static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
        bcm_writel(val, udc->iudma_regs + off);
 }
 
-static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off)
+static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off, int chan)
 {
-       return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+       return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off +
+                       (ENETDMA_CHAN_WIDTH * chan));
 }
 
-static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off,
+                                       int chan)
 {
-       bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+       bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off +
+                       (ENETDMA_CHAN_WIDTH * chan));
 }
 
-static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off)
+static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off, int chan)
 {
-       return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+       return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off +
+                       (ENETDMA_CHAN_WIDTH * chan));
 }
 
-static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off,
+                                       int chan)
 {
-       bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+       bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off +
+                       (ENETDMA_CHAN_WIDTH * chan));
 }
 
 static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled)
@@ -638,7 +644,7 @@ static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma,
        } while (!last_bd);
 
        usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK,
-                       ENETDMAC_CHANCFG_REG(iudma->ch_idx));
+                       ENETDMAC_CHANCFG_REG, iudma->ch_idx);
 }
 
 /**
@@ -694,9 +700,9 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
                bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num));
 
        /* stop DMA, then wait for the hardware to wrap up */
-       usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx));
+       usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG, ch_idx);
 
-       while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) &
+       while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx) &
                                   ENETDMAC_CHANCFG_EN_MASK) {
                udelay(1);
 
@@ -713,10 +719,10 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
                        dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n",
                                 ch_idx);
                        usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK,
-                                       ENETDMAC_CHANCFG_REG(ch_idx));
+                                       ENETDMAC_CHANCFG_REG, ch_idx);
                }
        }
-       usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx));
+       usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG, ch_idx);
 
        /* don't leave "live" HW-owned entries for the next guy to step on */
        for (d = iudma->bd_ring; d <= iudma->end_bd; d++)
@@ -728,11 +734,11 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
 
        /* set up IRQs, UBUS burst size, and BD base for this channel */
        usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
-                       ENETDMAC_IRMASK_REG(ch_idx));
-       usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx));
+                       ENETDMAC_IRMASK_REG, ch_idx);
+       usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG, ch_idx);
 
-       usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx));
-       usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx));
+       usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG, ch_idx);
+       usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG, ch_idx);
 }
 
 /**
@@ -2035,7 +2041,7 @@ static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id)
        spin_lock(&udc->lock);
 
        usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
-                       ENETDMAC_IR_REG(iudma->ch_idx));
+                       ENETDMAC_IR_REG, iudma->ch_idx);
        bep = iudma->bep;
        rc = iudma_read(udc, iudma);
 
@@ -2175,18 +2181,18 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)
                seq_printf(s, " [ep%d]:\n",
                           max_t(int, iudma_defaults[ch_idx].ep_num, 0));
                seq_printf(s, "  cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n",
-                          usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)),
-                          usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)),
-                          usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)),
-                          usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx)));
+                          usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx),
+                          usb_dmac_readl(udc, ENETDMAC_IR_REG, ch_idx),
+                          usb_dmac_readl(udc, ENETDMAC_IRMASK_REG, ch_idx),
+                          usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG, ch_idx));
 
-               sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx));
-               sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx));
+               sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG, ch_idx);
+               sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG, ch_idx);
                seq_printf(s, "  base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n",
-                          usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)),
+                          usb_dmas_readl(udc, ENETDMAS_RSTART_REG, ch_idx),
                           sram2 >> 16, sram2 & 0xffff,
                           sram3 >> 16, sram3 & 0xffff,
-                          usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx)));
+                          usb_dmas_readl(udc, ENETDMAS_SRAM4_REG, ch_idx));
                seq_printf(s, "  desc: %d/%d used", iudma->n_bds_used,
                           iudma->n_bds);
 
index 306a2b52125c8e7ee2eba91bcf1156e689ae133e..2b43343940766251ee5f274b807b882273f09008 100644 (file)
@@ -585,7 +585,6 @@ static ssize_t ffs_epfile_io(struct file *file,
                             char __user *buf, size_t len, int read)
 {
        struct ffs_epfile *epfile = file->private_data;
-       struct usb_gadget *gadget = epfile->ffs->gadget;
        struct ffs_ep *ep;
        char *data = NULL;
        ssize_t ret, data_len;
@@ -621,6 +620,12 @@ static ssize_t ffs_epfile_io(struct file *file,
 
        /* Allocate & copy */
        if (!halt) {
+               /*
+                * if we _do_ wait above, the epfile->ffs->gadget might be NULL
+                * before the waiting completes, so do not assign to 'gadget' earlier
+                */
+               struct usb_gadget *gadget = epfile->ffs->gadget;
+
                /*
                 * Controller may require buffer size to be aligned to
                 * maxpacketsize of an out endpoint.
index bf7a56b6d48ac2c3ebb3acf8920c70d79900d307..69b76efd11e9bea3f11d9d2effe293c04045f01c 100644 (file)
@@ -1157,7 +1157,7 @@ static int __init printer_bind_config(struct usb_configuration *c)
 
        usb_gadget_set_selfpowered(gadget);
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget)) {
                otg_descriptor.bmAttributes |= USB_OTG_HNP;
                printer_cfg_driver.descriptors = otg_desc;
                printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
index f04b2c3154dea73b0fa2c1d93322bdbf1c5930bc..dd9678f85c586a591b2a6514ba71034895d1769d 100644 (file)
@@ -1629,7 +1629,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
                ep->ep.desc = NULL;
                ep->halted = 0;
                INIT_LIST_HEAD(&ep->queue);
-               usb_ep_set_maxpacket_limit(&ep->ep, &ep->ep.maxpacket);
+               usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket);
        }
 }
 
index 471142725ffe1cd42f92b2ad0883fa925c715a2a..81cda09b47e3127772e51cbc5c57eab7761c4a52 100644 (file)
@@ -685,8 +685,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        u32                     status, masked_status, pcd_status = 0, cmd;
        int                     bh;
+       unsigned long           flags;
 
-       spin_lock (&ehci->lock);
+       /*
+        * For threadirqs option we use spin_lock_irqsave() variant to prevent
+        * deadlock with ehci hrtimer callback, because hrtimer callbacks run
+        * in interrupt context even when threadirqs is specified. We can go
+        * back to spin_lock() variant when hrtimer callbacks become threaded.
+        */
+       spin_lock_irqsave(&ehci->lock, flags);
 
        status = ehci_readl(ehci, &ehci->regs->status);
 
@@ -704,7 +711,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
        /* Shared IRQ? */
        if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
-               spin_unlock(&ehci->lock);
+               spin_unlock_irqrestore(&ehci->lock, flags);
                return IRQ_NONE;
        }
 
@@ -815,7 +822,7 @@ dead:
 
        if (bh)
                ehci_work (ehci);
-       spin_unlock (&ehci->lock);
+       spin_unlock_irqrestore(&ehci->lock, flags);
        if (pcd_status)
                usb_hcd_poll_rh_status(hcd);
        return IRQ_HANDLED;
index 47b858fc50b2ee484c035cef8fe8b27c669009b5..7ae0c4d517417d46dbc2dd8f51993728fa839c3a 100644 (file)
@@ -238,6 +238,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        int                     port;
        int                     mask;
        int                     changed;
+       bool                    fs_idle_delay;
 
        ehci_dbg(ehci, "suspend root hub\n");
 
@@ -272,6 +273,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        ehci->bus_suspended = 0;
        ehci->owned_ports = 0;
        changed = 0;
+       fs_idle_delay = false;
        port = HCS_N_PORTS(ehci->hcs_params);
        while (port--) {
                u32 __iomem     *reg = &ehci->regs->port_status [port];
@@ -300,16 +302,32 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                }
 
                if (t1 != t2) {
+                       /*
+                        * On some controllers, Wake-On-Disconnect will
+                        * generate false wakeup signals until the bus
+                        * switches over to full-speed idle.  For their
+                        * sake, add a delay if we need one.
+                        */
+                       if ((t2 & PORT_WKDISC_E) &&
+                                       ehci_port_speed(ehci, t2) ==
+                                               USB_PORT_STAT_HIGH_SPEED)
+                               fs_idle_delay = true;
                        ehci_writel(ehci, t2, reg);
                        changed = 1;
                }
        }
+       spin_unlock_irq(&ehci->lock);
+
+       if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) {
+               /*
+                * Wait for HCD to enter low-power mode or for the bus
+                * to switch to full-speed idle.
+                */
+               usleep_range(5000, 5500);
+       }
 
        if (changed && ehci->has_tdi_phy_lpm) {
-               spin_unlock_irq(&ehci->lock);
-               msleep(5);      /* 5 ms for HCD to enter low-power mode */
                spin_lock_irq(&ehci->lock);
-
                port = HCS_N_PORTS(ehci->hcs_params);
                while (port--) {
                        u32 __iomem     *hostpc_reg = &ehci->regs->hostpc[port];
@@ -322,8 +340,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                                        port, (t3 & HOSTPC_PHCD) ?
                                        "succeeded" : "failed");
                }
+               spin_unlock_irq(&ehci->lock);
        }
-       spin_unlock_irq(&ehci->lock);
 
        /* Apparently some devices need a >= 1-uframe delay here */
        if (ehci->bus_suspended)
index 6fe577d46fa2d392e586d608efc3805666ac452c..924a6ccdb622777a6fc71b21dfb6a0ee0792f536 100644 (file)
@@ -4733,6 +4733,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        /* Accept arbitrarily long scatter-gather lists */
        hcd->self.sg_tablesize = ~0;
 
+       /* support to build packet from discontinuous buffers */
+       hcd->self.no_sg_constraint = 1;
+
        /* XHCI controllers don't stop the ep queue on short packets :| */
        hcd->self.no_stop_on_short = 1;
 
@@ -4757,14 +4760,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
                /* xHCI private pointer was set in xhci_pci_probe for the second
                 * registered roothub.
                 */
-               xhci = hcd_to_xhci(hcd);
-               /*
-                * Support arbitrarily aligned sg-list entries on hosts without
-                * TD fragment rules (which are currently unsupported).
-                */
-               if (xhci->hci_version < 0x100)
-                       hcd->self.no_sg_constraint = 1;
-
                return 0;
        }
 
@@ -4793,9 +4788,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        if (xhci->hci_version > 0x96)
                xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
 
-       if (xhci->hci_version < 0x100)
-               hcd->self.no_sg_constraint = 1;
-
        /* Make sure the HC is halted. */
        retval = xhci_halt(xhci);
        if (retval)
index fc192ad9cc6a60eb4a7f00d124eb0a0d1bca73fe..239ad0b1ceb6d15ddff5fa3741ca97796e70e067 100644 (file)
@@ -477,8 +477,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                musb->port1_status |=
                                                (USB_PORT_STAT_C_SUSPEND << 16)
                                                | MUSB_PORT_STAT_RESUME;
+                               musb->rh_timer = jiffies
+                                                + msecs_to_jiffies(20);
                                schedule_delayed_work(
-                                       &musb->finish_resume_work, 20);
+                                       &musb->finish_resume_work,
+                                       msecs_to_jiffies(20));
 
                                musb->xceiv->state = OTG_STATE_A_HOST;
                                musb->is_active = 1;
@@ -2157,11 +2160,19 @@ static void musb_restore_context(struct musb *musb)
        void __iomem *musb_base = musb->mregs;
        void __iomem *ep_target_regs;
        void __iomem *epio;
+       u8 power;
 
        musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
        musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
        musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
-       musb_writeb(musb_base, MUSB_POWER, musb->context.power);
+
+       /* Don't affect SUSPENDM/RESUME bits in POWER reg */
+       power = musb_readb(musb_base, MUSB_POWER);
+       power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME;
+       musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME);
+       power |= musb->context.power;
+       musb_writeb(musb_base, MUSB_POWER, power);
+
        musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe);
        musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);
        musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
index ed455724017b5767f6ad849961946d7ad7af3228..abb38c3833ef46a1f8041c8a5f95fa96138b1796 100644 (file)
@@ -1183,6 +1183,9 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
                                csr = MUSB_CSR0_H_STATUSPKT
                                        | MUSB_CSR0_TXPKTRDY;
 
+                       /* disable ping token in status phase */
+                       csr |= MUSB_CSR0_H_DIS_PING;
+
                        /* flag status stage */
                        musb->ep0_stage = MUSB_EP0_STATUS;
 
index eb634433ef095b631cd7e70df77453334cf48ddc..e2d2d8c9891bc1f7a4cf5f8a16048d58a3d4c630 100644 (file)
@@ -135,7 +135,8 @@ void musb_port_suspend(struct musb *musb, bool do_suspend)
 
                /* later, GetPortStatus will stop RESUME signaling */
                musb->port1_status |= MUSB_PORT_STAT_RESUME;
-               schedule_delayed_work(&musb->finish_resume_work, 20);
+               schedule_delayed_work(&musb->finish_resume_work,
+                                     msecs_to_jiffies(20));
        }
 }
 
@@ -158,7 +159,6 @@ void musb_port_reset(struct musb *musb, bool do_reset)
         */
        power = musb_readb(mbase, MUSB_POWER);
        if (do_reset) {
-
                /*
                 * If RESUME is set, we must make sure it stays minimum 20 ms.
                 * Then we must clear RESUME and wait a bit to let musb start
@@ -167,11 +167,22 @@ void musb_port_reset(struct musb *musb, bool do_reset)
                 * detected".
                 */
                if (power &  MUSB_POWER_RESUME) {
-                       while (time_before(jiffies, musb->rh_timer))
-                               msleep(1);
+                       long remain = (unsigned long) musb->rh_timer - jiffies;
+
+                       if (musb->rh_timer > 0 && remain > 0) {
+                               /* take into account the minimum delay after resume */
+                               schedule_delayed_work(
+                                       &musb->deassert_reset_work, remain);
+                               return;
+                       }
+
                        musb_writeb(mbase, MUSB_POWER,
-                               power & ~MUSB_POWER_RESUME);
-                       msleep(1);
+                                   power & ~MUSB_POWER_RESUME);
+
+                       /* Give the core 1 ms to clear MUSB_POWER_RESUME */
+                       schedule_delayed_work(&musb->deassert_reset_work,
+                                             msecs_to_jiffies(1));
+                       return;
                }
 
                power &= 0xf0;
@@ -180,7 +191,8 @@ void musb_port_reset(struct musb *musb, bool do_reset)
 
                musb->port1_status |= USB_PORT_STAT_RESET;
                musb->port1_status &= ~USB_PORT_STAT_ENABLE;
-               schedule_delayed_work(&musb->deassert_reset_work, 50);
+               schedule_delayed_work(&musb->deassert_reset_work,
+                                     msecs_to_jiffies(50));
        } else {
                dev_dbg(musb->controller, "root port reset stopped\n");
                musb_writeb(mbase, MUSB_POWER,
index 2a408cdaf7b2c7102098faac6d29727505f41c91..8aa59a2c5eb2485c823244012cc738ce5df7d127 100644 (file)
@@ -659,7 +659,6 @@ static int omap2430_runtime_suspend(struct device *dev)
                                OTG_INTERFSEL);
 
                omap2430_low_level_exit(musb);
-               phy_power_off(musb->phy);
        }
 
        return 0;
@@ -674,7 +673,6 @@ static int omap2430_runtime_resume(struct device *dev)
                omap2430_low_level_init(musb);
                musb_writel(musb->mregs, OTG_INTERFSEL,
                                musb->context.otg_interfsel);
-               phy_power_on(musb->phy);
        }
 
        return 0;
index 8546c8dccd51b003fc9aba3038184cd2d0eedbea..d204f745ed05e652ef168940dece89e2e16a8269 100644 (file)
@@ -159,32 +159,6 @@ put_3p3:
        return rc;
 }
 
-#ifdef CONFIG_PM_SLEEP
-#define USB_PHY_SUSP_DIG_VOL  500000
-static int msm_hsusb_config_vddcx(int high)
-{
-       int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
-       int min_vol;
-       int ret;
-
-       if (high)
-               min_vol = USB_PHY_VDD_DIG_VOL_MIN;
-       else
-               min_vol = USB_PHY_SUSP_DIG_VOL;
-
-       ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
-       if (ret) {
-               pr_err("%s: unable to set the voltage for regulator "
-                       "HSUSB_VDDCX\n", __func__);
-               return ret;
-       }
-
-       pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
-
-       return ret;
-}
-#endif
-
 static int msm_hsusb_ldo_set_mode(int on)
 {
        int ret = 0;
@@ -440,7 +414,32 @@ static int msm_otg_reset(struct usb_phy *phy)
 #define PHY_SUSPEND_TIMEOUT_USEC       (500 * 1000)
 #define PHY_RESUME_TIMEOUT_USEC        (100 * 1000)
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
+
+#define USB_PHY_SUSP_DIG_VOL  500000
+static int msm_hsusb_config_vddcx(int high)
+{
+       int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
+       int min_vol;
+       int ret;
+
+       if (high)
+               min_vol = USB_PHY_VDD_DIG_VOL_MIN;
+       else
+               min_vol = USB_PHY_SUSP_DIG_VOL;
+
+       ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
+       if (ret) {
+               pr_err("%s: unable to set the voltage for regulator "
+                       "HSUSB_VDDCX\n", __func__);
+               return ret;
+       }
+
+       pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
+
+       return ret;
+}
+
 static int msm_otg_suspend(struct msm_otg *motg)
 {
        struct usb_phy *phy = &motg->phy;
@@ -1733,22 +1732,18 @@ static int msm_otg_pm_resume(struct device *dev)
 }
 #endif
 
-#ifdef CONFIG_PM
 static const struct dev_pm_ops msm_otg_dev_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
        SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
                                msm_otg_runtime_idle)
 };
-#endif
 
 static struct platform_driver msm_otg_driver = {
        .remove = msm_otg_remove,
        .driver = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
-#ifdef CONFIG_PM
                .pm = &msm_otg_dev_pm_ops,
-#endif
        },
 };
 
index ee1f00f03c434ec67a5fee98f229ca3fd8e6c187..44ab1298680557f840d243056d7fc4812d7adc0d 100644 (file)
@@ -907,6 +907,8 @@ static const struct usb_device_id id_table_combined[] = {
        /* Crucible Devices */
        { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) },
+       /* Cressi Devices */
+       { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) },
        { }                                     /* Terminating entry */
 };
 
index 1e2d369df86e57ae29f188040fcf9b2d85aaa49c..e599fbfcde5f8fd5055f29f464fdaea13c130cb5 100644 (file)
  * Manufacturer: Smart GSM Team
  */
 #define FTDI_Z3X_PID           0x0011
+
+/*
+ * Product: Cressi PC Interface
+ * Manufacturer: Cressi
+ */
+#define FTDI_CRESSI_PID                0x87d0
index 216d20affba82741e0430989e19da8a54a492037..68fc9fe65936e712ba08e9f6825de4773b4cc9a9 100644 (file)
@@ -1526,7 +1526,8 @@ static const struct usb_device_id option_ids[] = {
        /* Cinterion */
        { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
        { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
-       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8),
+               .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },
        { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
                .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
index 4fb7a8f83c8a99ff8d3412a5328b2407c98409a8..54af4e93369583e5629a4bac6d1ecdbd74f885cf 100644 (file)
@@ -186,12 +186,12 @@ static bool is_invalid_reserved_pfn(unsigned long pfn)
        if (pfn_valid(pfn)) {
                bool reserved;
                struct page *tail = pfn_to_page(pfn);
-               struct page *head = compound_trans_head(tail);
+               struct page *head = compound_head(tail);
                reserved = !!(PageReserved(head));
                if (head != tail) {
                        /*
                         * "head" is not a dangling pointer
-                        * (compound_trans_head takes care of that)
+                        * (compound_head takes care of that)
                         * but the hugepage may have been split
                         * from under us (and we may not hold a
                         * reference count on the head page so it can
index 0a025b8e2a12efd2f58434b8084a45ad2454b604..e48d4a672580cd5eefaf741946435073a4e58e8c 100644 (file)
@@ -1001,6 +1001,12 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                        break;
                }
 
+               /* virtio-scsi spec requires byte 0 of the lun to be 1 */
+               if (unlikely(v_req.lun[0] != 1)) {
+                       vhost_scsi_send_bad_target(vs, vq, head, out);
+                       continue;
+               }
+
                /* Extract the tpgt */
                target = v_req.lun[1];
                tpg = ACCESS_ONCE(vs_tpg[target]);
index aaf2995d37f4b595d010efa500e89bb1ae5aef5b..68b45fc9ba6a5de684f18128ca337c09e7b3657e 100644 (file)
@@ -402,7 +402,7 @@ static int __init wdt_init(void)
 
        if (!found) {
                pr_err("No W83697HF/HG could be found\n");
-               ret = -EIO;
+               ret = -ENODEV;
                goto out;
        }
 
index 0129b78a69086b3ba2d53f24ab6d54b23faf6862..4f70f383132cc9dfe143c570fbb9759967fefc6f 100644 (file)
@@ -458,11 +458,10 @@ static int bio_integrity_verify(struct bio *bio)
        struct blk_integrity_exchg bix;
        struct bio_vec *bv;
        sector_t sector = bio->bi_integrity->bip_iter.bi_sector;
-       unsigned int sectors, total, ret;
+       unsigned int sectors, ret = 0;
        void *prot_buf = bio->bi_integrity->bip_buf;
        int i;
 
-       ret = total = 0;
        bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
        bix.sector_size = bi->sector_size;
 
@@ -484,8 +483,6 @@ static int bio_integrity_verify(struct bio *bio)
                sectors = bv->bv_len / bi->sector_size;
                sector += sectors;
                prot_buf += sectors * bi->tuple_size;
-               total += sectors * bi->tuple_size;
-               BUG_ON(total > bio->bi_integrity->bip_iter.bi_size);
 
                kunmap_atomic(kaddr);
        }
index cf32f03933694cb56fd518a5e25388f35d834162..c0f3718b77a83e7e0e010b089e436356e83a1eb7 100644 (file)
@@ -513,7 +513,7 @@ struct cifs_mnt_data {
 static inline unsigned int
 get_rfc1002_length(void *buf)
 {
-       return be32_to_cpu(*((__be32 *)buf));
+       return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
 }
 
 static inline void
index 53c15074bb3622b9a251bef0eafeed866a24ce0b..834fce759d8075313261dfa0a01c76ba9c2cb5b3 100644 (file)
@@ -2579,31 +2579,19 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
        struct cifsInodeInfo *cinode = CIFS_I(inode);
        struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
        ssize_t rc = -EACCES;
+       loff_t lock_pos = pos;
 
-       BUG_ON(iocb->ki_pos != pos);
-
+       if (file->f_flags & O_APPEND)
+               lock_pos = i_size_read(inode);
        /*
         * We need to hold the sem to be sure nobody modifies lock list
         * with a brlock that prevents writing.
         */
        down_read(&cinode->lock_sem);
-       if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
+       if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs),
                                     server->vals->exclusive_lock_type, NULL,
-                                    CIFS_WRITE_OP)) {
-               mutex_lock(&inode->i_mutex);
-               rc = __generic_file_aio_write(iocb, iov, nr_segs,
-                                              &iocb->ki_pos);
-               mutex_unlock(&inode->i_mutex);
-       }
-
-       if (rc > 0) {
-               ssize_t err;
-
-               err = generic_write_sync(file, iocb->ki_pos - rc, rc);
-               if (err < 0)
-                       rc = err;
-       }
-
+                                    CIFS_WRITE_OP))
+               rc = generic_file_aio_write(iocb, iov, nr_segs, pos);
        up_read(&cinode->lock_sem);
        return rc;
 }
index b375709528467b5a1a74e078fae2aeb7813e1a1e..18cd5650a5fc6106394691f6ee5baf37f5d8d49b 100644 (file)
@@ -270,6 +270,26 @@ cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
                iov->iov_len = rqst->rq_pagesz;
 }
 
+static unsigned long
+rqst_len(struct smb_rqst *rqst)
+{
+       unsigned int i;
+       struct kvec *iov = rqst->rq_iov;
+       unsigned long buflen = 0;
+
+       /* total up iov array first */
+       for (i = 0; i < rqst->rq_nvec; i++)
+               buflen += iov[i].iov_len;
+
+       /* add in the page array if there is one */
+       if (rqst->rq_npages) {
+               buflen += rqst->rq_pagesz * (rqst->rq_npages - 1);
+               buflen += rqst->rq_tailsz;
+       }
+
+       return buflen;
+}
+
 static int
 smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
@@ -277,6 +297,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        struct kvec *iov = rqst->rq_iov;
        int n_vec = rqst->rq_nvec;
        unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
+       unsigned long send_length;
        unsigned int i;
        size_t total_len = 0, sent;
        struct socket *ssocket = server->ssocket;
@@ -285,6 +306,14 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        if (ssocket == NULL)
                return -ENOTSOCK;
 
+       /* sanity check send length */
+       send_length = rqst_len(rqst);
+       if (send_length != smb_buf_length + 4) {
+               WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
+                       send_length, smb_buf_length);
+               return -EIO;
+       }
+
        cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
        dump_smb(iov[0].iov_base, iov[0].iov_len);
 
index db25c2bdfe464035be537cee3fc09acad77e8cdb..60a45e9f53231379c87b9ee75cb64eb8d6d71979 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -683,35 +683,65 @@ EXPORT_SYMBOL(fget_raw);
  * The fput_needed flag returned by fget_light should be passed to the
  * corresponding fput_light.
  */
-struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
+static unsigned long __fget_light(unsigned int fd, fmode_t mask)
 {
        struct files_struct *files = current->files;
        struct file *file;
 
-       *fput_needed = 0;
        if (atomic_read(&files->count) == 1) {
                file = __fcheck_files(files, fd);
-               if (file && (file->f_mode & mask))
-                       file = NULL;
+               if (!file || unlikely(file->f_mode & mask))
+                       return 0;
+               return (unsigned long)file;
        } else {
                file = __fget(fd, mask);
-               if (file)
-                       *fput_needed = 1;
+               if (!file)
+                       return 0;
+               return FDPUT_FPUT | (unsigned long)file;
        }
-
-       return file;
 }
-struct file *fget_light(unsigned int fd, int *fput_needed)
+unsigned long __fdget(unsigned int fd)
 {
-       return __fget_light(fd, FMODE_PATH, fput_needed);
+       return __fget_light(fd, FMODE_PATH);
 }
-EXPORT_SYMBOL(fget_light);
+EXPORT_SYMBOL(__fdget);
 
-struct file *fget_raw_light(unsigned int fd, int *fput_needed)
+unsigned long __fdget_raw(unsigned int fd)
 {
-       return __fget_light(fd, 0, fput_needed);
+       return __fget_light(fd, 0);
+}
+
+unsigned long __fdget_pos(unsigned int fd)
+{
+       struct files_struct *files = current->files;
+       struct file *file;
+       unsigned long v;
+
+       if (atomic_read(&files->count) == 1) {
+               file = __fcheck_files(files, fd);
+               v = 0;
+       } else {
+               file = __fget(fd, 0);
+               v = FDPUT_FPUT;
+       }
+       if (!file)
+               return 0;
+
+       if (file->f_mode & FMODE_ATOMIC_POS) {
+               if (file_count(file) > 1) {
+                       v |= FDPUT_POS_UNLOCK;
+                       mutex_lock(&file->f_pos_lock);
+               }
+       }
+       return v | (unsigned long)file;
 }
 
+/*
+ * We only lock f_pos if we have threads or if the file might be
+ * shared with another process. In both cases we'll have an elevated
+ * file count (done either by fdget() or by fork()).
+ */
+
 void set_close_on_exec(unsigned int fd, int flag)
 {
        struct files_struct *files = current->files;
index 5fff9030be34df26aff0c0ed56081aee1306bf02..5b24008ea4f678b668ff2a52fa41f1812b579645 100644 (file)
@@ -135,6 +135,7 @@ struct file *get_empty_filp(void)
        atomic_long_set(&f->f_count, 1);
        rwlock_init(&f->f_owner.lock);
        spin_lock_init(&f->f_lock);
+       mutex_init(&f->f_pos_lock);
        eventpoll_init_file(f);
        /* f->f_version: 0 */
        return f;
index e0259a163f98e69000c28bdb78fcf2b77c2bed2d..d754e3cf99a85af0c433e71846db6ee051751ebd 100644 (file)
 struct wb_writeback_work {
        long nr_pages;
        struct super_block *sb;
-       /*
-        * Write only inodes dirtied before this time. Don't forget to set
-        * older_than_this_is_set when you set this.
-        */
-       unsigned long older_than_this;
+       unsigned long *older_than_this;
        enum writeback_sync_modes sync_mode;
        unsigned int tagged_writepages:1;
        unsigned int for_kupdate:1;
        unsigned int range_cyclic:1;
        unsigned int for_background:1;
        unsigned int for_sync:1;        /* sync(2) WB_SYNC_ALL writeback */
-       unsigned int older_than_this_is_set:1;
        enum wb_reason reason;          /* why was writeback initiated? */
 
        struct list_head list;          /* pending work list */
@@ -252,10 +247,10 @@ static int move_expired_inodes(struct list_head *delaying_queue,
        int do_sb_sort = 0;
        int moved = 0;
 
-       WARN_ON_ONCE(!work->older_than_this_is_set);
        while (!list_empty(delaying_queue)) {
                inode = wb_inode(delaying_queue->prev);
-               if (inode_dirtied_after(inode, work->older_than_this))
+               if (work->older_than_this &&
+                   inode_dirtied_after(inode, *work->older_than_this))
                        break;
                list_move(&inode->i_wb_list, &tmp);
                moved++;
@@ -742,8 +737,6 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
                .sync_mode      = WB_SYNC_NONE,
                .range_cyclic   = 1,
                .reason         = reason,
-               .older_than_this = jiffies,
-               .older_than_this_is_set = 1,
        };
 
        spin_lock(&wb->list_lock);
@@ -802,13 +795,12 @@ static long wb_writeback(struct bdi_writeback *wb,
 {
        unsigned long wb_start = jiffies;
        long nr_pages = work->nr_pages;
+       unsigned long oldest_jif;
        struct inode *inode;
        long progress;
 
-       if (!work->older_than_this_is_set) {
-               work->older_than_this = jiffies;
-               work->older_than_this_is_set = 1;
-       }
+       oldest_jif = jiffies;
+       work->older_than_this = &oldest_jif;
 
        spin_lock(&wb->list_lock);
        for (;;) {
@@ -842,10 +834,10 @@ static long wb_writeback(struct bdi_writeback *wb,
                 * safe.
                 */
                if (work->for_kupdate) {
-                       work->older_than_this = jiffies -
+                       oldest_jif = jiffies -
                                msecs_to_jiffies(dirty_expire_interval * 10);
                } else if (work->for_background)
-                       work->older_than_this = jiffies;
+                       oldest_jif = jiffies;
 
                trace_writeback_start(wb->bdi, work);
                if (list_empty(&wb->b_io))
@@ -1357,21 +1349,18 @@ EXPORT_SYMBOL(try_to_writeback_inodes_sb);
 
 /**
  * sync_inodes_sb      -       sync sb inode pages
- * @sb:                        the superblock
- * @older_than_this:   timestamp
+ * @sb: the superblock
  *
  * This function writes and waits on any dirty inode belonging to this
- * superblock that has been dirtied before given timestamp.
+ * super_block.
  */
-void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this)
+void sync_inodes_sb(struct super_block *sb)
 {
        DECLARE_COMPLETION_ONSTACK(done);
        struct wb_writeback_work work = {
                .sb             = sb,
                .sync_mode      = WB_SYNC_ALL,
                .nr_pages       = LONG_MAX,
-               .older_than_this = older_than_this,
-               .older_than_this_is_set = 1,
                .range_cyclic   = 0,
                .done           = &done,
                .reason         = WB_REASON_SYNC,
index 968ce411db53e807b6f3b0fd216cd6730f226b5d..32602c667b4aaf697c97b7f7e709d808328a5468 100644 (file)
@@ -103,6 +103,8 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry,
                folder = &entry->folder;
                memset(folder, 0, sizeof(*folder));
                folder->type = cpu_to_be16(HFSPLUS_FOLDER);
+               if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags))
+                       folder->flags |= cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT);
                folder->id = cpu_to_be32(inode->i_ino);
                HFSPLUS_I(inode)->create_date =
                        folder->create_date =
@@ -203,6 +205,36 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
        return hfs_brec_find(fd, hfs_find_rec_by_key);
 }
 
+static void hfsplus_subfolders_inc(struct inode *dir)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
+
+       if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
+               /*
+                * Increment subfolder count. Note, the value is only meaningful
+                * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set.
+                */
+               HFSPLUS_I(dir)->subfolders++;
+       }
+}
+
+static void hfsplus_subfolders_dec(struct inode *dir)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
+
+       if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
+               /*
+                * Decrement subfolder count. Note, the value is only meaningful
+                * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set.
+                *
+                * Check for zero. Some subfolders may have been created
+                * by an implementation ignorant of this counter.
+                */
+               if (HFSPLUS_I(dir)->subfolders)
+                       HFSPLUS_I(dir)->subfolders--;
+       }
+}
+
 int hfsplus_create_cat(u32 cnid, struct inode *dir,
                struct qstr *str, struct inode *inode)
 {
@@ -247,6 +279,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
                goto err1;
 
        dir->i_size++;
+       if (S_ISDIR(inode->i_mode))
+               hfsplus_subfolders_inc(dir);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
        hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
 
@@ -336,6 +370,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
                goto out;
 
        dir->i_size--;
+       if (type == HFSPLUS_FOLDER)
+               hfsplus_subfolders_dec(dir);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
        hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
 
@@ -380,6 +416,7 @@ int hfsplus_rename_cat(u32 cnid,
 
        hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset,
                                src_fd.entrylength);
+       type = be16_to_cpu(entry.type);
 
        /* create new dir entry with the data from the old entry */
        hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
@@ -394,6 +431,8 @@ int hfsplus_rename_cat(u32 cnid,
        if (err)
                goto out;
        dst_dir->i_size++;
+       if (type == HFSPLUS_FOLDER)
+               hfsplus_subfolders_inc(dst_dir);
        dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
 
        /* finally remove the old entry */
@@ -405,6 +444,8 @@ int hfsplus_rename_cat(u32 cnid,
        if (err)
                goto out;
        src_dir->i_size--;
+       if (type == HFSPLUS_FOLDER)
+               hfsplus_subfolders_dec(src_dir);
        src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
 
        /* remove old thread entry */
index 08846425b67ffa112b7978650e1521b74955a1dc..62d571eb69bae9c7d04b5c27238b9fa2a1d4a633 100644 (file)
@@ -242,6 +242,7 @@ struct hfsplus_inode_info {
         */
        sector_t fs_blocks;
        u8 userflags;           /* BSD user file flags */
+       u32 subfolders;         /* Subfolder count (HFSX only) */
        struct list_head open_dir_list;
        loff_t phys_size;
 
index 8ffb3a8ffe75b9d6374cb9198d83d5dce5553457..5a126828d85eb011714b067976f0a14981103c7c 100644 (file)
@@ -261,7 +261,7 @@ struct hfsplus_cat_folder {
        struct DInfo user_info;
        struct DXInfo finder_info;
        __be32 text_encoding;
-       u32 reserved;
+       __be32 subfolders;      /* Subfolder count in HFSX. Reserved in HFS+. */
 } __packed;
 
 /* HFS file info (stolen from hfs.h) */
@@ -301,11 +301,13 @@ struct hfsplus_cat_file {
        struct hfsplus_fork_raw rsrc_fork;
 } __packed;
 
-/* File attribute bits */
+/* File and folder flag bits */
 #define HFSPLUS_FILE_LOCKED            0x0001
 #define HFSPLUS_FILE_THREAD_EXISTS     0x0002
 #define HFSPLUS_XATTR_EXISTS           0x0004
 #define HFSPLUS_ACL_EXISTS             0x0008
+#define HFSPLUS_HAS_FOLDER_COUNT       0x0010  /* Folder has subfolder count
+                                                * (HFSX only) */
 
 /* HFS+ catalog thread (part of a cat_entry) */
 struct hfsplus_cat_thread {
index fa929f325f87502074d66e208c1a57feba089c82..a4f45bd88a631ad5a153a8f45fdd1044a3637c1c 100644 (file)
@@ -375,6 +375,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
        hip->extent_state = 0;
        hip->flags = 0;
        hip->userflags = 0;
+       hip->subfolders = 0;
        memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
        memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
        hip->alloc_blocks = 0;
@@ -494,6 +495,10 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
                HFSPLUS_I(inode)->create_date = folder->create_date;
                HFSPLUS_I(inode)->fs_blocks = 0;
+               if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
+                       HFSPLUS_I(inode)->subfolders =
+                               be32_to_cpu(folder->subfolders);
+               }
                inode->i_op = &hfsplus_dir_inode_operations;
                inode->i_fop = &hfsplus_dir_operations;
        } else if (type == HFSPLUS_FILE) {
@@ -566,6 +571,10 @@ int hfsplus_cat_write_inode(struct inode *inode)
                folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
                folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
                folder->valence = cpu_to_be32(inode->i_size - 2);
+               if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
+                       folder->subfolders =
+                               cpu_to_be32(HFSPLUS_I(inode)->subfolders);
+               }
                hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
                                         sizeof(struct hfsplus_cat_folder));
        } else if (HFSPLUS_IS_RSRC(inode)) {
index 968eab5bc1f5623f09169c65f178518dbd87ee2b..68537e8b7a0934859048ecd4cfb0e67cdcb6b819 100644 (file)
@@ -75,7 +75,7 @@ int hfsplus_parse_options_remount(char *input, int *force)
        int token;
 
        if (!input)
-               return 0;
+               return 1;
 
        while ((p = strsep(&input, ",")) != NULL) {
                if (!*p)
index 0d6ce895a9eec0ce3b3329d1353b594d353aeacb..0f4152defe7b6f96afa752acdbc075a512bc8c5d 100644 (file)
@@ -94,6 +94,7 @@ const void *kernfs_super_ns(struct super_block *sb)
  * @fs_type: file_system_type of the fs being mounted
  * @flags: mount flags specified for the mount
  * @root: kernfs_root of the hierarchy being mounted
+ * @new_sb_created: tell the caller if we allocated a new superblock
  * @ns: optional namespace tag of the mount
  *
  * This is to be called from each kernfs user's file_system_type->mount()
@@ -104,7 +105,8 @@ const void *kernfs_super_ns(struct super_block *sb)
  * The return value can be passed to the vfs layer verbatim.
  */
 struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
-                              struct kernfs_root *root, const void *ns)
+                              struct kernfs_root *root, bool *new_sb_created,
+                              const void *ns)
 {
        struct super_block *sb;
        struct kernfs_super_info *info;
@@ -122,6 +124,10 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
                kfree(info);
        if (IS_ERR(sb))
                return ERR_CAST(sb);
+
+       if (new_sb_created)
+               *new_sb_created = !sb->s_root;
+
        if (!sb->s_root) {
                error = kernfs_fill_super(sb);
                if (error) {
index 385f7817bfccbd12fbc352c39827586d4cf953d7..2f730ef9b4b3da78afd6a830c13c7ba13c706ffe 100644 (file)
@@ -1884,7 +1884,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
 
                nd->path = f.file->f_path;
                if (flags & LOOKUP_RCU) {
-                       if (f.need_put)
+                       if (f.flags & FDPUT_FPUT)
                                *fp = f.file;
                        nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
                        rcu_read_lock();
index ef792f29f831c4c72e3e4edd7db9257165aca2fe..5d8ccecf5f5caada2de94bf30689ecd9e725a15a 100644 (file)
@@ -659,16 +659,19 @@ int nfs_async_inode_return_delegation(struct inode *inode,
 
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
+       if (delegation == NULL)
+               goto out_enoent;
 
-       if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
-               rcu_read_unlock();
-               return -ENOENT;
-       }
+       if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
+               goto out_enoent;
        nfs_mark_return_delegation(server, delegation);
        rcu_read_unlock();
 
        nfs_delegation_run_state_manager(clp);
        return 0;
+out_enoent:
+       rcu_read_unlock();
+       return -ENOENT;
 }
 
 static struct inode *
index 28a0a3cbd3b7818ee255f3a3c57b738d098e48c3..360114ae8b829bf705eaf4feda49b8fe484de2c0 100644 (file)
@@ -164,17 +164,16 @@ static void nfs_zap_caches_locked(struct inode *inode)
        if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
                nfs_fscache_invalidate(inode);
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR
-                                       | NFS_INO_INVALID_LABEL
                                        | NFS_INO_INVALID_DATA
                                        | NFS_INO_INVALID_ACCESS
                                        | NFS_INO_INVALID_ACL
                                        | NFS_INO_REVAL_PAGECACHE;
        } else
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR
-                                       | NFS_INO_INVALID_LABEL
                                        | NFS_INO_INVALID_ACCESS
                                        | NFS_INO_INVALID_ACL
                                        | NFS_INO_REVAL_PAGECACHE;
+       nfs_zap_label_cache_locked(nfsi);
 }
 
 void nfs_zap_caches(struct inode *inode)
@@ -266,6 +265,13 @@ nfs_init_locked(struct inode *inode, void *opaque)
 }
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
+static void nfs_clear_label_invalid(struct inode *inode)
+{
+       spin_lock(&inode->i_lock);
+       NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_LABEL;
+       spin_unlock(&inode->i_lock);
+}
+
 void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
                                        struct nfs4_label *label)
 {
@@ -283,6 +289,7 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
                                        __func__,
                                        (char *)label->label,
                                        label->len, error);
+               nfs_clear_label_invalid(inode);
        }
 }
 
@@ -1648,7 +1655,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                inode->i_blocks = fattr->du.nfs2.blocks;
 
        /* Update attrtimeo value if we're out of the unstable period */
-       if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) {
+       if (invalid & NFS_INO_INVALID_ATTR) {
                nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = now;
@@ -1661,7 +1668,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                }
        }
        invalid &= ~NFS_INO_INVALID_ATTR;
-       invalid &= ~NFS_INO_INVALID_LABEL;
        /* Don't invalidate the data if we were to blame */
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
                                || S_ISLNK(inode->i_mode)))
index 8b5cc04a86115e05f0a2e98e9b02a0b307b1b910..b46cf5a6732952460c68f6faeeb5479f355868d7 100644 (file)
@@ -176,7 +176,8 @@ extern struct nfs_server *nfs4_create_server(
 extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
                                                      struct nfs_fh *);
 extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
-                                       struct sockaddr *sap, size_t salen);
+                                       struct sockaddr *sap, size_t salen,
+                                       struct net *net);
 extern void nfs_free_server(struct nfs_server *server);
 extern struct nfs_server *nfs_clone_server(struct nfs_server *,
                                           struct nfs_fh *,
@@ -279,9 +280,18 @@ static inline void nfs4_label_free(struct nfs4_label *label)
        }
        return;
 }
+
+static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi)
+{
+       if (nfs_server_capable(&nfsi->vfs_inode, NFS_CAP_SECURITY_LABEL))
+               nfsi->cache_validity |= NFS_INO_INVALID_LABEL;
+}
 #else
 static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; }
 static inline void nfs4_label_free(void *label) {}
+static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi)
+{
+}
 #endif /* CONFIG_NFS_V4_SECURITY_LABEL */
 
 /* proc.c */
index aa9bc973f36a31eacbca297c71f2cd9bb5fb81e9..a462ef0fb5d6dcda8bab6f211e8122d7d972b070 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/lockd/bind.h>
 #include <linux/nfs_mount.h>
 #include <linux/freezer.h>
+#include <linux/xattr.h>
 
 #include "iostat.h"
 #include "internal.h"
index 860ad26a55905be060c1bcd1db5e9dde11746eec..0e46d3d1b6cc6c06854517c66ab4aa5f783cfb9e 100644 (file)
@@ -1135,6 +1135,7 @@ static int nfs_probe_destination(struct nfs_server *server)
  * @hostname: new end-point's hostname
  * @sap: new end-point's socket address
  * @salen: size of "sap"
+ * @net: net namespace
  *
  * The nfs_server must be quiescent before this function is invoked.
  * Either its session is drained (NFSv4.1+), or its transport is
@@ -1143,13 +1144,13 @@ static int nfs_probe_destination(struct nfs_server *server)
  * Returns zero on success, or a negative errno value.
  */
 int nfs4_update_server(struct nfs_server *server, const char *hostname,
-                      struct sockaddr *sap, size_t salen)
+                      struct sockaddr *sap, size_t salen, struct net *net)
 {
        struct nfs_client *clp = server->nfs_client;
        struct rpc_clnt *clnt = server->client;
        struct xprt_create xargs = {
                .ident          = clp->cl_proto,
-               .net            = &init_net,
+               .net            = net,
                .dstaddr        = sap,
                .addrlen        = salen,
                .servername     = hostname,
@@ -1189,7 +1190,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
        error = nfs4_set_client(server, hostname, sap, salen, buf,
                                clp->cl_rpcclient->cl_auth->au_flavor,
                                clp->cl_proto, clnt->cl_timeout,
-                               clp->cl_minorversion, clp->cl_net);
+                               clp->cl_minorversion, net);
        nfs_put_client(clp);
        if (error != 0) {
                nfs_server_insert_lists(server);
index 12c8132ad4081a3937c12ceebc991d1f61048093..b9a35c05b60f7f418ce91443d46dab88c690ca69 100644 (file)
@@ -324,8 +324,9 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
                        &rdata->res.seq_res,
                        task))
                return;
-       nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
-                       rdata->args.lock_context, FMODE_READ);
+       if (nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
+                       rdata->args.lock_context, FMODE_READ) == -EIO)
+               rpc_exit(task, -EIO); /* lost lock, terminate I/O */
 }
 
 static void filelayout_read_call_done(struct rpc_task *task, void *data)
@@ -435,8 +436,9 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
                        &wdata->res.seq_res,
                        task))
                return;
-       nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
-                       wdata->args.lock_context, FMODE_WRITE);
+       if (nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
+                       wdata->args.lock_context, FMODE_WRITE) == -EIO)
+               rpc_exit(task, -EIO); /* lost lock, terminate I/O */
 }
 
 static void filelayout_write_call_done(struct rpc_task *task, void *data)
index 4e7f05d3e9db77d1fe96533424362c4171201014..3d5dbf80d46a8c844bf7fd96c6db6935bb76d48b 100644 (file)
@@ -121,9 +121,8 @@ static int nfs4_validate_fspath(struct dentry *dentry,
 }
 
 static size_t nfs_parse_server_name(char *string, size_t len,
-               struct sockaddr *sa, size_t salen, struct nfs_server *server)
+               struct sockaddr *sa, size_t salen, struct net *net)
 {
-       struct net *net = rpc_net_ns(server->client);
        ssize_t ret;
 
        ret = rpc_pton(net, string, len, sa, salen);
@@ -223,6 +222,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
                                     const struct nfs4_fs_location *location)
 {
        const size_t addr_bufsize = sizeof(struct sockaddr_storage);
+       struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client);
        struct vfsmount *mnt = ERR_PTR(-ENOENT);
        char *mnt_path;
        unsigned int maxbuflen;
@@ -248,8 +248,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
                        continue;
 
                mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
-                               mountdata->addr, addr_bufsize,
-                               NFS_SB(mountdata->sb));
+                               mountdata->addr, addr_bufsize, net);
                if (mountdata->addrlen == 0)
                        continue;
 
@@ -419,6 +418,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
                const struct nfs4_fs_location *location)
 {
        const size_t addr_bufsize = sizeof(struct sockaddr_storage);
+       struct net *net = rpc_net_ns(server->client);
        struct sockaddr *sap;
        unsigned int s;
        size_t salen;
@@ -440,7 +440,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
                        continue;
 
                salen = nfs_parse_server_name(buf->data, buf->len,
-                                               sap, addr_bufsize, server);
+                                               sap, addr_bufsize, net);
                if (salen == 0)
                        continue;
                rpc_set_port(sap, NFS_PORT);
@@ -450,7 +450,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
                if (hostname == NULL)
                        break;
 
-               error = nfs4_update_server(server, hostname, sap, salen);
+               error = nfs4_update_server(server, hostname, sap, salen, net);
                kfree(hostname);
                if (error == 0)
                        break;
index 2da6a698b8f7719c14eefec65e6148a48d030bb3..450bfedbe2f4c0f88cacc44ec504872487279faa 100644 (file)
@@ -2398,13 +2398,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 
        if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
                /* Use that stateid */
-       } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
+       } else if (truncate && state != NULL) {
                struct nfs_lockowner lockowner = {
                        .l_owner = current->files,
                        .l_pid = current->tgid,
                };
-               nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
-                               &lockowner);
+               if (!nfs4_valid_open_stateid(state))
+                       return -EBADF;
+               if (nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
+                               &lockowner) == -EIO)
+                       return -EBADF;
        } else
                nfs4_stateid_copy(&arg.stateid, &zero_stateid);
 
@@ -4011,8 +4014,9 @@ static bool nfs4_stateid_is_current(nfs4_stateid *stateid,
 {
        nfs4_stateid current_stateid;
 
-       if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode))
-               return false;
+       /* If the current stateid represents a lost lock, then exit */
+       if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode) == -EIO)
+               return true;
        return nfs4_stateid_match(stateid, &current_stateid);
 }
 
@@ -5828,8 +5832,7 @@ struct nfs_release_lockowner_data {
        struct nfs4_lock_state *lsp;
        struct nfs_server *server;
        struct nfs_release_lockowner_args args;
-       struct nfs4_sequence_args seq_args;
-       struct nfs4_sequence_res seq_res;
+       struct nfs_release_lockowner_res res;
        unsigned long timestamp;
 };
 
@@ -5837,7 +5840,7 @@ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata
 {
        struct nfs_release_lockowner_data *data = calldata;
        nfs40_setup_sequence(data->server,
-                               &data->seq_args, &data->seq_res, task);
+                               &data->args.seq_args, &data->res.seq_res, task);
        data->timestamp = jiffies;
 }
 
@@ -5846,7 +5849,7 @@ static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
        struct nfs_release_lockowner_data *data = calldata;
        struct nfs_server *server = data->server;
 
-       nfs40_sequence_done(task, &data->seq_res);
+       nfs40_sequence_done(task, &data->res.seq_res);
 
        switch (task->tk_status) {
        case 0:
@@ -5887,7 +5890,6 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
                return -ENOMEM;
-       nfs4_init_sequence(&data->seq_args, &data->seq_res, 0);
        data->lsp = lsp;
        data->server = server;
        data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
@@ -5895,6 +5897,8 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
        data->args.lock_owner.s_dev = server->s_dev;
 
        msg.rpc_argp = &data->args;
+       msg.rpc_resp = &data->res;
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
        return 0;
 }
index e5be72518bd7ebe813522b1c24f7fa16b539421e..0deb32105ccf3cb8b40fe95365f91f8b4b9c4da4 100644 (file)
@@ -974,9 +974,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
        else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
                nfs4_stateid_copy(dst, &lsp->ls_stateid);
                ret = 0;
-               smp_rmb();
-               if (!list_empty(&lsp->ls_seqid.list))
-                       ret = -EWOULDBLOCK;
        }
        spin_unlock(&state->state_lock);
        nfs4_put_lock_state(lsp);
@@ -984,10 +981,9 @@ out:
        return ret;
 }
 
-static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
 {
        const nfs4_stateid *src;
-       int ret;
        int seq;
 
        do {
@@ -996,12 +992,7 @@ static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
                if (test_bit(NFS_OPEN_STATE, &state->flags))
                        src = &state->open_stateid;
                nfs4_stateid_copy(dst, src);
-               ret = 0;
-               smp_rmb();
-               if (!list_empty(&state->owner->so_seqid.list))
-                       ret = -EWOULDBLOCK;
        } while (read_seqretry(&state->seqlock, seq));
-       return ret;
 }
 
 /*
@@ -1015,15 +1006,19 @@ int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
        if (ret == -EIO)
                /* A lost lock - don't even consider delegations */
                goto out;
-       if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
+       /* returns true if delegation stateid found and copied */
+       if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) {
+               ret = 0;
                goto out;
+       }
        if (ret != -ENOENT)
                /* nfs4_copy_delegation_stateid() didn't over-write
                 * dst, so it still has the lock stateid which we now
                 * choose to use.
                 */
                goto out;
-       ret = nfs4_copy_open_stateid(dst, state);
+       nfs4_copy_open_stateid(dst, state);
+       ret = 0;
 out:
        if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
                dst->seqid = 0;
index 0b9ff4395e6ac320f6108f7c3cabb2d57d5a426f..abc8cbcfe90e0fca9f67471740c0b41c9055b7c6 100644 (file)
@@ -86,7 +86,7 @@ static int dnotify_handle_event(struct fsnotify_group *group,
                                struct fsnotify_mark *inode_mark,
                                struct fsnotify_mark *vfsmount_mark,
                                u32 mask, void *data, int data_type,
-                               const unsigned char *file_name)
+                               const unsigned char *file_name, u32 cookie)
 {
        struct dnotify_mark *dn_mark;
        struct dnotify_struct *dn;
index 0e792f5e3147c3cfcf38a980716075ea509b0e46..dc638f786d5c762373288942dc04cc5c5cee0750 100644 (file)
@@ -147,7 +147,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
                                 struct fsnotify_mark *inode_mark,
                                 struct fsnotify_mark *fanotify_mark,
                                 u32 mask, void *data, int data_type,
-                                const unsigned char *file_name)
+                                const unsigned char *file_name, u32 cookie)
 {
        int ret = 0;
        struct fanotify_event_info *event;
@@ -192,10 +192,12 @@ static int fanotify_handle_event(struct fsnotify_group *group,
 
        ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge);
        if (ret) {
-               BUG_ON(mask & FAN_ALL_PERM_EVENTS);
+               /* Permission events shouldn't be merged */
+               BUG_ON(ret == 1 && mask & FAN_ALL_PERM_EVENTS);
                /* Our event wasn't used in the end. Free it. */
                fsnotify_destroy_event(group, fsn_event);
-               ret = 0;
+
+               return 0;
        }
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
index b6175fa11bf856809d1ee6a43ee9b861980e9160..287a22c041496a206d94daa299be55a20b4786a2 100644 (file)
@@ -698,6 +698,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        struct fsnotify_group *group;
        int f_flags, fd;
        struct user_struct *user;
+       struct fanotify_event_info *oevent;
 
        pr_debug("%s: flags=%d event_f_flags=%d\n",
                __func__, flags, event_f_flags);
@@ -730,8 +731,20 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        group->fanotify_data.user = user;
        atomic_inc(&user->fanotify_listeners);
 
+       oevent = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
+       if (unlikely(!oevent)) {
+               fd = -ENOMEM;
+               goto out_destroy_group;
+       }
+       group->overflow_event = &oevent->fse;
+       fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
+       oevent->tgid = get_pid(task_tgid(current));
+       oevent->path.mnt = NULL;
+       oevent->path.dentry = NULL;
+
        group->fanotify_data.f_flags = event_f_flags;
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+       oevent->response = 0;
        mutex_init(&group->fanotify_data.access_mutex);
        init_waitqueue_head(&group->fanotify_data.access_waitq);
        INIT_LIST_HEAD(&group->fanotify_data.access_list);
index 1d4e1ea2f37ca4995db3f16db9bd00bbf862ca93..9d3e9c50066aaf5856350cf3bc85576a79bab900 100644 (file)
@@ -179,7 +179,7 @@ static int send_to_group(struct inode *to_tell,
 
        return group->ops->handle_event(group, to_tell, inode_mark,
                                        vfsmount_mark, mask, data, data_is,
-                                       file_name);
+                                       file_name, cookie);
 }
 
 /*
index ee674fe2cec7f3f7b99ad09363b6a425ff4d6dbd..ad199598045655105e7ba4db0ed639357bf3fc6f 100644 (file)
@@ -55,6 +55,13 @@ void fsnotify_destroy_group(struct fsnotify_group *group)
        /* clear the notification queue of all events */
        fsnotify_flush_notify(group);
 
+       /*
+        * Destroy overflow event (we cannot use fsnotify_destroy_event() as
+        * that deliberately ignores overflow events.
+        */
+       if (group->overflow_event)
+               group->ops->free_event(group->overflow_event);
+
        fsnotify_put_group(group);
 }
 
@@ -99,7 +106,6 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
        INIT_LIST_HEAD(&group->marks_list);
 
        group->ops = ops;
-       fsnotify_init_event(&group->overflow_event, NULL, FS_Q_OVERFLOW);
 
        return group;
 }
index 485eef3f4407a0371d903c08a75c9f262dfde82e..ed855ef6f0775e447489e7dd43e00ff3891c850e 100644 (file)
@@ -27,6 +27,6 @@ extern int inotify_handle_event(struct fsnotify_group *group,
                                struct fsnotify_mark *inode_mark,
                                struct fsnotify_mark *vfsmount_mark,
                                u32 mask, void *data, int data_type,
-                               const unsigned char *file_name);
+                               const unsigned char *file_name, u32 cookie);
 
 extern const struct fsnotify_ops inotify_fsnotify_ops;
index d5ee56348bb803fd0ddff46d4f3da7d0fa7016d1..43ab1e1a07a20acaca5a4741487ac5121e00bbd4 100644 (file)
@@ -67,7 +67,7 @@ int inotify_handle_event(struct fsnotify_group *group,
                         struct fsnotify_mark *inode_mark,
                         struct fsnotify_mark *vfsmount_mark,
                         u32 mask, void *data, int data_type,
-                        const unsigned char *file_name)
+                        const unsigned char *file_name, u32 cookie)
 {
        struct inotify_inode_mark *i_mark;
        struct inotify_event_info *event;
@@ -103,6 +103,7 @@ int inotify_handle_event(struct fsnotify_group *group,
        fsn_event = &event->fse;
        fsnotify_init_event(fsn_event, inode, mask);
        event->wd = i_mark->wd;
+       event->sync_cookie = cookie;
        event->name_len = len;
        if (len)
                strcpy(event->name, file_name);
index 497395c8274bc62cd0fab6c2cf89ce4950fafffc..78a2ca3966c3857a8f4a5bf5369b63ad10ef3380 100644 (file)
@@ -495,7 +495,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
 
        /* Queue ignore event for the watch */
        inotify_handle_event(group, NULL, fsn_mark, NULL, FS_IN_IGNORED,
-                            NULL, FSNOTIFY_EVENT_NONE, NULL);
+                            NULL, FSNOTIFY_EVENT_NONE, NULL, 0);
 
        i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
        /* remove this mark from the idr */
@@ -633,11 +633,23 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
 static struct fsnotify_group *inotify_new_group(unsigned int max_events)
 {
        struct fsnotify_group *group;
+       struct inotify_event_info *oevent;
 
        group = fsnotify_alloc_group(&inotify_fsnotify_ops);
        if (IS_ERR(group))
                return group;
 
+       oevent = kmalloc(sizeof(struct inotify_event_info), GFP_KERNEL);
+       if (unlikely(!oevent)) {
+               fsnotify_destroy_group(group);
+               return ERR_PTR(-ENOMEM);
+       }
+       group->overflow_event = &oevent->fse;
+       fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
+       oevent->wd = -1;
+       oevent->sync_cookie = 0;
+       oevent->name_len = 0;
+
        group->max_events = max_events;
 
        spin_lock_init(&group->inotify_data.idr_lock);
index 18b3c4427dcac0f2c9125581cc171be3f1eb3a9f..1e58402171a56cd9d078ab62307951689a5630df 100644 (file)
@@ -80,7 +80,8 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
 /*
  * Add an event to the group notification queue.  The group can later pull this
  * event off the queue to deal with.  The function returns 0 if the event was
- * added to the queue, 1 if the event was merged with some other queued event.
+ * added to the queue, 1 if the event was merged with some other queued event,
+ * 2 if the queue of events has overflown.
  */
 int fsnotify_add_notify_event(struct fsnotify_group *group,
                              struct fsnotify_event *event,
@@ -95,10 +96,14 @@ int fsnotify_add_notify_event(struct fsnotify_group *group,
        mutex_lock(&group->notification_mutex);
 
        if (group->q_len >= group->max_events) {
+               ret = 2;
                /* Queue overflow event only if it isn't already queued */
-               if (list_empty(&group->overflow_event.list))
-                       event = &group->overflow_event;
-               ret = 1;
+               if (!list_empty(&group->overflow_event->list)) {
+                       mutex_unlock(&group->notification_mutex);
+                       return ret;
+               }
+               event = group->overflow_event;
+               goto queue;
        }
 
        if (!list_empty(list) && merge) {
@@ -109,6 +114,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group,
                }
        }
 
+queue:
        group->q_len++;
        list_add_tail(&event->list, list);
        mutex_unlock(&group->notification_mutex);
@@ -132,7 +138,11 @@ struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group
 
        event = list_first_entry(&group->notification_list,
                                 struct fsnotify_event, list);
-       list_del(&event->list);
+       /*
+        * We need to init list head for the case of overflow event so that
+        * check in fsnotify_add_notify_events() works
+        */
+       list_del_init(&event->list);
        group->q_len--;
 
        return event;
index 8450262bcf2a782777bafd01fdd3b9b58f0bd318..51632c40e896fd0b7c4e4c87b2afc5dc4f418aca 100644 (file)
@@ -2393,8 +2393,8 @@ out_dio:
 
        if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
            ((file->f_flags & O_DIRECT) && !direct_io)) {
-               ret = filemap_fdatawrite_range(file->f_mapping, pos,
-                                              pos + count - 1);
+               ret = filemap_fdatawrite_range(file->f_mapping, *ppos,
+                                              *ppos + count - 1);
                if (ret < 0)
                        written = ret;
 
@@ -2407,8 +2407,8 @@ out_dio:
                }
 
                if (!ret)
-                       ret = filemap_fdatawait_range(file->f_mapping, pos,
-                                                     pos + count - 1);
+                       ret = filemap_fdatawait_range(file->f_mapping, *ppos,
+                                                     *ppos + count - 1);
        }
 
        /*
index aaa50611ec66c27f2b6cd9a67a039a05e0253787..d7b5108789e2e7d8a26049b7dc6a01f8a0ff2d6f 100644 (file)
@@ -717,6 +717,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
         */
        if (status < 0)
                mlog_errno(status);
+       /*
+        * Clear dq_off so that we search for the structure in quota file next
+        * time we acquire it. The structure might be deleted and reallocated
+        * elsewhere by another node while our dquot structure is on freelist.
+        */
+       dquot->dq_off = 0;
        clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
 out_trans:
        ocfs2_commit_trans(osb, handle);
@@ -756,16 +762,17 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
        status = ocfs2_lock_global_qf(info, 1);
        if (status < 0)
                goto out;
-       if (!test_bit(DQ_READ_B, &dquot->dq_flags)) {
-               status = ocfs2_qinfo_lock(info, 0);
-               if (status < 0)
-                       goto out_dq;
-               status = qtree_read_dquot(&info->dqi_gi, dquot);
-               ocfs2_qinfo_unlock(info, 0);
-               if (status < 0)
-                       goto out_dq;
-       }
-       set_bit(DQ_READ_B, &dquot->dq_flags);
+       status = ocfs2_qinfo_lock(info, 0);
+       if (status < 0)
+               goto out_dq;
+       /*
+        * We always want to read dquot structure from disk because we don't
+        * know what happened with it while it was on freelist.
+        */
+       status = qtree_read_dquot(&info->dqi_gi, dquot);
+       ocfs2_qinfo_unlock(info, 0);
+       if (status < 0)
+               goto out_dq;
 
        OCFS2_DQUOT(dquot)->dq_use_count++;
        OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
index 2e4344be3b962b40a6cd4e5743a87f088b7abe63..2001862bf2b1cfbb20ed78bd9febeacbc96b42a4 100644 (file)
@@ -1303,10 +1303,6 @@ int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
        ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
 
 out:
-       /* Clear the read bit so that next time someone uses this
-        * dquot he reads fresh info from disk and allocates local
-        * dquot structure */
-       clear_bit(DQ_READ_B, &dquot->dq_flags);
        return status;
 }
 
index 4b3e1edf2fe4d917e69e56b3e268e32f2ae7301a..b9ed8b25c108c69d68889b5b6eadac9878eb7bd9 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -705,6 +705,10 @@ static int do_dentry_open(struct file *f,
                return 0;
        }
 
+       /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
+       if (S_ISREG(inode->i_mode))
+               f->f_mode |= FMODE_ATOMIC_POS;
+
        f->f_op = fops_get(inode->i_fop);
        if (unlikely(WARN_ON(!f->f_op))) {
                error = -ENODEV;
index 51507065263b29e3b915a6aa2238630fe3f7ac67..b9760628e1fde7b9a5c681798a65185144abeb92 100644 (file)
@@ -1824,6 +1824,7 @@ static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
        if (rc)
                goto out_mmput;
 
+       rc = -ENOENT;
        down_read(&mm->mmap_sem);
        vma = find_exact_vma(mm, vm_start, vm_end);
        if (vma && vma->vm_file) {
index 02174a610315ebb218880a8744e05b2244b6d26f..e647c55275d9ff9f96b92ac859e65c10fc03d318 100644 (file)
@@ -121,9 +121,8 @@ u64 stable_page_flags(struct page *page)
         * just checks PG_head/PG_tail, so we need to check PageLRU/PageAnon
         * to make sure a given page is a thp, not a non-huge compound page.
         */
-       else if (PageTransCompound(page) &&
-                (PageLRU(compound_trans_head(page)) ||
-                 PageAnon(compound_trans_head(page))))
+       else if (PageTransCompound(page) && (PageLRU(compound_head(page)) ||
+                                            PageAnon(compound_head(page))))
                u |= 1 << KPF_THP;
 
        /*
index 831d49a4111f8405716d96ff6a451fc9ebd59e91..cfc8dcc160437c0daacd234f43d29faeb9b2fd33 100644 (file)
@@ -581,9 +581,17 @@ int dquot_scan_active(struct super_block *sb,
                dqstats_inc(DQST_LOOKUPS);
                dqput(old_dquot);
                old_dquot = dquot;
-               ret = fn(dquot, priv);
-               if (ret < 0)
-                       goto out;
+               /*
+                * ->release_dquot() can be racing with us. Our reference
+                * protects us from new calls to it so just wait for any
+                * outstanding call and recheck the DQ_ACTIVE_B after that.
+                */
+               wait_on_dquot(dquot);
+               if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
+                       ret = fn(dquot, priv);
+                       if (ret < 0)
+                               goto out;
+               }
                spin_lock(&dq_list_lock);
                /* We are safe to continue now because our dquot could not
                 * be moved out of the inuse list while we hold the reference */
index edc5746a902a090ce4dbda6b8b1205e729dff5b3..54e19b9392dc74381fec154fe3f0ceab32ce9bd8 100644 (file)
@@ -264,10 +264,22 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence)
 }
 EXPORT_SYMBOL(vfs_llseek);
 
+static inline struct fd fdget_pos(int fd)
+{
+       return __to_fd(__fdget_pos(fd));
+}
+
+static inline void fdput_pos(struct fd f)
+{
+       if (f.flags & FDPUT_POS_UNLOCK)
+               mutex_unlock(&f.file->f_pos_lock);
+       fdput(f);
+}
+
 SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
 {
        off_t retval;
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        if (!f.file)
                return -EBADF;
 
@@ -278,7 +290,7 @@ SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
                if (res != (loff_t)retval)
                        retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
        }
-       fdput(f);
+       fdput_pos(f);
        return retval;
 }
 
@@ -498,7 +510,7 @@ static inline void file_pos_write(struct file *file, loff_t pos)
 
 SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -506,7 +518,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
                ret = vfs_read(f.file, buf, count, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
        return ret;
 }
@@ -514,7 +526,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
 SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
                size_t, count)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -522,7 +534,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
                ret = vfs_write(f.file, buf, count, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
 
        return ret;
@@ -797,7 +809,7 @@ EXPORT_SYMBOL(vfs_writev);
 SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
                unsigned long, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -805,7 +817,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
                ret = vfs_readv(f.file, vec, vlen, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
 
        if (ret > 0)
@@ -817,7 +829,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
 SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
                unsigned long, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -825,7 +837,7 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
                ret = vfs_writev(f.file, vec, vlen, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
 
        if (ret > 0)
@@ -968,7 +980,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
                const struct compat_iovec __user *,vec,
                compat_ulong_t, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret;
        loff_t pos;
 
@@ -978,7 +990,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
        ret = compat_readv(f.file, vec, vlen, &pos);
        if (ret >= 0)
                f.file->f_pos = pos;
-       fdput(f);
+       fdput_pos(f);
        return ret;
 }
 
@@ -1035,7 +1047,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
                const struct compat_iovec __user *, vec,
                compat_ulong_t, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret;
        loff_t pos;
 
@@ -1045,7 +1057,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
        ret = compat_writev(f.file, vec, vlen, &pos);
        if (ret >= 0)
                f.file->f_pos = pos;
-       fdput(f);
+       fdput_pos(f);
        return ret;
 }
 
index e8ba024a055b5a55d6320ba38edf1338c7d90e65..b28d1dd10e8b70194a604a1fca654237edd817be 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
  * wait == 1 case since in that case write_inode() functions do
  * sync_dirty_buffer() and thus effectively write one block at a time.
  */
-static int __sync_filesystem(struct super_block *sb, int wait,
-                            unsigned long start)
+static int __sync_filesystem(struct super_block *sb, int wait)
 {
        if (wait)
-               sync_inodes_sb(sb, start);
+               sync_inodes_sb(sb);
        else
                writeback_inodes_sb(sb, WB_REASON_SYNC);
 
@@ -48,7 +47,6 @@ static int __sync_filesystem(struct super_block *sb, int wait,
 int sync_filesystem(struct super_block *sb)
 {
        int ret;
-       unsigned long start = jiffies;
 
        /*
         * We need to be protected against the filesystem going from
@@ -62,17 +60,17 @@ int sync_filesystem(struct super_block *sb)
        if (sb->s_flags & MS_RDONLY)
                return 0;
 
-       ret = __sync_filesystem(sb, 0, start);
+       ret = __sync_filesystem(sb, 0);
        if (ret < 0)
                return ret;
-       return __sync_filesystem(sb, 1, start);
+       return __sync_filesystem(sb, 1);
 }
 EXPORT_SYMBOL_GPL(sync_filesystem);
 
 static void sync_inodes_one_sb(struct super_block *sb, void *arg)
 {
        if (!(sb->s_flags & MS_RDONLY))
-               sync_inodes_sb(sb, *((unsigned long *)arg));
+               sync_inodes_sb(sb);
 }
 
 static void sync_fs_one_sb(struct super_block *sb, void *arg)
@@ -104,10 +102,9 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
 SYSCALL_DEFINE0(sync)
 {
        int nowait = 0, wait = 1;
-       unsigned long start = jiffies;
 
        wakeup_flusher_threads(0, WB_REASON_SYNC);
-       iterate_supers(sync_inodes_one_sb, &start);
+       iterate_supers(sync_inodes_one_sb, NULL);
        iterate_supers(sync_fs_one_sb, &nowait);
        iterate_supers(sync_fs_one_sb, &wait);
        iterate_bdevs(fdatawrite_one_bdev, NULL);
index 6211230814fd89dcc1a0a4b0acbabe000428e5b8..3eaf5c6622eb4fafc82137bc501aac803d7952f4 100644 (file)
@@ -27,6 +27,7 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 {
        struct dentry *root;
        void *ns;
+       bool new_sb;
 
        if (!(flags & MS_KERNMOUNT)) {
                if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
@@ -37,8 +38,8 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
        }
 
        ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
-       root = kernfs_mount_ns(fs_type, flags, sysfs_root, ns);
-       if (IS_ERR(root))
+       root = kernfs_mount_ns(fs_type, flags, sysfs_root, &new_sb, ns);
+       if (IS_ERR(root) || !new_sb)
                kobj_ns_drop(KOBJ_NS_TYPE_NET, ns);
        return root;
 }
index c02a27a19c6df0984eb3ea13fc5a06c5e251aaa5..1037637957c7670e1a66e6bf1a8e51c80fbcc49d 100644 (file)
@@ -144,6 +144,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        size_t count = iocb->ki_nbytes;
        struct udf_inode_info *iinfo = UDF_I(inode);
 
+       mutex_lock(&inode->i_mutex);
        down_write(&iinfo->i_data_sem);
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
                if (file->f_flags & O_APPEND)
@@ -156,6 +157,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                                                pos + count)) {
                        err = udf_expand_file_adinicb(inode);
                        if (err) {
+                               mutex_unlock(&inode->i_mutex);
                                udf_debug("udf_expand_adinicb: err=%d\n", err);
                                return err;
                        }
@@ -169,9 +171,17 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        } else
                up_write(&iinfo->i_data_sem);
 
-       retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
-       if (retval > 0)
+       retval = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
+       mutex_unlock(&inode->i_mutex);
+
+       if (retval > 0) {
+               ssize_t err;
+
                mark_inode_dirty(inode);
+               err = generic_write_sync(file, iocb->ki_pos - retval, retval);
+               if (err < 0)
+                       retval = err;
+       }
 
        return retval;
 }
index 062b7925bca04c02949919ac37aab790d7b982a2..982ce05c87ed61c86dfc9200731a28f2db44b70b 100644 (file)
@@ -265,6 +265,7 @@ int udf_expand_file_adinicb(struct inode *inode)
                .nr_to_write = 1,
        };
 
+       WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
        if (!iinfo->i_lenAlloc) {
                if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
                        iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
index f35d5c953ff953dcde133c4b55568d1920db3589..9ddfb8190ca1cd56b5f1cd2247e9f54925fce68f 100644 (file)
@@ -705,7 +705,6 @@ xfs_setattr_size(
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct inode            *inode = VFS_I(ip);
-       int                     mask = iattr->ia_valid;
        xfs_off_t               oldsize, newsize;
        struct xfs_trans        *tp;
        int                     error;
@@ -726,8 +725,8 @@ xfs_setattr_size(
 
        ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
        ASSERT(S_ISREG(ip->i_d.di_mode));
-       ASSERT((mask & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
-                       ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
+       ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
+               ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
 
        oldsize = inode->i_size;
        newsize = iattr->ia_size;
@@ -736,7 +735,7 @@ xfs_setattr_size(
         * Short circuit the truncate case for zero length files.
         */
        if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) {
-               if (!(mask & (ATTR_CTIME|ATTR_MTIME)))
+               if (!(iattr->ia_valid & (ATTR_CTIME|ATTR_MTIME)))
                        return 0;
 
                /*
@@ -824,10 +823,11 @@ xfs_setattr_size(
         * these flags set.  For all other operations the VFS set these flags
         * explicitly if it wants a timestamp update.
         */
-       if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
+       if (newsize != oldsize &&
+           !(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) {
                iattr->ia_ctime = iattr->ia_mtime =
                        current_fs_time(inode->i_sb);
-               mask |= ATTR_CTIME | ATTR_MTIME;
+               iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;
        }
 
        /*
@@ -863,9 +863,9 @@ xfs_setattr_size(
                xfs_inode_clear_eofblocks_tag(ip);
        }
 
-       if (mask & ATTR_MODE)
+       if (iattr->ia_valid & ATTR_MODE)
                xfs_setattr_mode(ip, iattr);
-       if (mask & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
+       if (iattr->ia_valid & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
                xfs_setattr_time(ip, iattr);
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
index cdebd832c3dba1fcd937869d1cedcebe09113c25..4ef6fdbced78b7e99680f9e4e8afbb502a7bce92 100644 (file)
@@ -205,16 +205,25 @@ xlog_cil_insert_format_items(
                /*
                 * We 64-bit align the length of each iovec so that the start
                 * of the next one is naturally aligned.  We'll need to
-                * account for that slack space here.
+                * account for that slack space here. Then round nbytes up
+                * to 64-bit alignment so that the initial buffer alignment is
+                * easy to calculate and verify.
                 */
                nbytes += niovecs * sizeof(uint64_t);
+               nbytes = round_up(nbytes, sizeof(uint64_t));
 
                /* grab the old item if it exists for reservation accounting */
                old_lv = lip->li_lv;
 
-               /* calc buffer size */
-               buf_size = sizeof(struct xfs_log_vec) + nbytes +
-                               niovecs * sizeof(struct xfs_log_iovec);
+               /*
+                * The data buffer needs to start 64-bit aligned, so round up
+                * that space to ensure we can align it appropriately and not
+                * overrun the buffer.
+                */
+               buf_size = nbytes +
+                          round_up((sizeof(struct xfs_log_vec) +
+                                    niovecs * sizeof(struct xfs_log_iovec)),
+                                   sizeof(uint64_t));
 
                /* compare to existing item size */
                if (lip->li_lv && buf_size <= lip->li_lv->lv_size) {
@@ -251,6 +260,8 @@ xlog_cil_insert_format_items(
                /* The allocated data region lies beyond the iovec region */
                lv->lv_buf_len = 0;
                lv->lv_buf = (char *)lv + buf_size - nbytes;
+               ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t)));
+
                lip->li_ops->iop_format(lip, lv);
 insert:
                ASSERT(lv->lv_buf_len <= nbytes);
index 02df7b408a2623d6a32e7a2bc8285be9348ca646..f96c05669a9e06298980bd14e377e34536d0119b 100644 (file)
@@ -282,22 +282,29 @@ xfs_readsb(
        struct xfs_sb   *sbp = &mp->m_sb;
        int             error;
        int             loud = !(flags & XFS_MFSI_QUIET);
+       const struct xfs_buf_ops *buf_ops;
 
        ASSERT(mp->m_sb_bp == NULL);
        ASSERT(mp->m_ddev_targp != NULL);
 
+       /*
+        * For the initial read, we must guess at the sector
+        * size based on the block device.  It's enough to
+        * get the sb_sectsize out of the superblock and
+        * then reread with the proper length.
+        * We don't verify it yet, because it may not be complete.
+        */
+       sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
+       buf_ops = NULL;
+
        /*
         * Allocate a (locked) buffer to hold the superblock.
         * This will be kept around at all times to optimize
         * access to the superblock.
         */
-       sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
-
 reread:
        bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
-                                  BTOBB(sector_size), 0,
-                                  loud ? &xfs_sb_buf_ops
-                                       : &xfs_sb_quiet_buf_ops);
+                                  BTOBB(sector_size), 0, buf_ops);
        if (!bp) {
                if (loud)
                        xfs_warn(mp, "SB buffer read failed");
@@ -328,12 +335,13 @@ reread:
        }
 
        /*
-        * If device sector size is smaller than the superblock size,
-        * re-read the superblock so the buffer is correctly sized.
+        * Re-read the superblock so the buffer is correctly sized,
+        * and properly verified.
         */
-       if (sector_size < sbp->sb_sectsize) {
+       if (buf_ops == NULL) {
                xfs_buf_relse(bp);
                sector_size = sbp->sb_sectsize;
+               buf_ops = loud ? &xfs_sb_buf_ops : &xfs_sb_quiet_buf_ops;
                goto reread;
        }
 
index b7c9aea77f8fd2e7ca88537df77536eca8148418..1e116794bb6622d686487f36a461f8f644fd27c2 100644 (file)
@@ -295,8 +295,7 @@ xfs_mount_validate_sb(
            sbp->sb_dblocks == 0                                        ||
            sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)                      ||
            sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) {
-               XFS_CORRUPTION_ERROR("SB sanity check failed",
-                               XFS_ERRLEVEL_LOW, mp, sbp);
+               xfs_notice(mp, "SB sanity check failed");
                return XFS_ERROR(EFSCORRUPTED);
        }
 
@@ -611,10 +610,10 @@ xfs_sb_read_verify(
                                                XFS_SB_VERSION_5) ||
             dsb->sb_crc != 0)) {
 
-               if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize),
+               if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
                                      offsetof(struct xfs_sb, sb_crc))) {
                        /* Only fail bad secondaries on a known V5 filesystem */
-                       if (bp->b_bn != XFS_SB_DADDR &&
+                       if (bp->b_bn == XFS_SB_DADDR ||
                            xfs_sb_version_hascrc(&mp->m_sb)) {
                                error = EFSCORRUPTED;
                                goto out_error;
@@ -625,7 +624,7 @@ xfs_sb_read_verify(
 
 out_error:
        if (error) {
-               if (error != EWRONGFS)
+               if (error == EFSCORRUPTED)
                        XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
                                             mp, bp->b_addr);
                xfs_buf_ioerror(bp, error);
@@ -644,7 +643,6 @@ xfs_sb_quiet_read_verify(
 {
        struct xfs_dsb  *dsb = XFS_BUF_TO_SBP(bp);
 
-
        if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) {
                /* XFS filesystem, verify noisily! */
                xfs_sb_read_verify(bp);
index f317488263dd975eb85eb44d9746abfb974ef46f..d971f4932b5d8bb92d5efe645f372462abfbbe81 100644 (file)
@@ -913,7 +913,7 @@ xfs_flush_inodes(
        struct super_block      *sb = mp->m_super;
 
        if (down_read_trylock(&sb->s_umount)) {
-               sync_inodes_sb(sb, jiffies);
+               sync_inodes_sb(sb);
                up_read(&sb->s_umount);
        }
 }
index a1116a3b54ef106b610e74cc54ac0326b76805f6..8c1603b10665d141a2b0cb67e2643c0db7452146 100644 (file)
 #define TEGRA124_CLK_PWM 17
 #define TEGRA124_CLK_I2S2 18
 /* 20 (register bit affects vi and vi_sensor) */
-#define TEGRA124_CLK_GR_2D 21
+/* 21 */
 #define TEGRA124_CLK_USBD 22
 #define TEGRA124_CLK_ISP 23
-#define TEGRA124_CLK_GR_3D 24
+/* 26 */
 /* 25 */
 #define TEGRA124_CLK_DISP2 26
 #define TEGRA124_CLK_DISP1 27
index be85127bfed3a2da2a58a3284a48b7e72094ca91..f27000f55a83d6a27921372f9890520e492a747b 100644 (file)
@@ -171,6 +171,11 @@ static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 add
        return 0;
 }
 
+static inline int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
+{
+       return -ENXIO;
+}
+
 static inline int kvm_vgic_init(struct kvm *kvm)
 {
        return 0;
index aa865a9a4c4f862b4aa693ed9918399b338e7696..ec1464df4c60930a7fde38f1bc6f35a35b7f79d3 100644 (file)
@@ -43,6 +43,7 @@ struct mq_attr;
 struct mqstat;
 struct audit_watch;
 struct audit_tree;
+struct sk_buff;
 
 struct audit_krule {
        int                     vers_ops;
@@ -463,7 +464,7 @@ extern int audit_filter_user(int type);
 extern int audit_filter_type(int type);
 extern int audit_rule_change(int type, __u32 portid, int seq,
                                void *data, size_t datasz);
-extern int audit_list_rules_send(__u32 portid, int seq);
+extern int audit_list_rules_send(struct sk_buff *request_skb, int seq);
 
 extern u32 audit_enabled;
 #else /* CONFIG_AUDIT */
index 18ba8a627f46e0fd77a97aa0257940d845f7f8a4..2ff2e8d982bea9b689050a2802fba5ec29e44b81 100644 (file)
@@ -121,8 +121,7 @@ void blk_mq_init_commands(struct request_queue *, void (*init)(void *data, struc
 
 void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);
 
-void blk_mq_insert_request(struct request_queue *, struct request *,
-               bool, bool);
+void blk_mq_insert_request(struct request *, bool, bool, bool);
 void blk_mq_run_queues(struct request_queue *q, bool async);
 void blk_mq_free_request(struct request *rq);
 bool blk_mq_can_queue(struct blk_mq_hw_ctx *);
@@ -134,7 +133,13 @@ struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *, const int ctx_ind
 struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_reg *, unsigned int);
 void blk_mq_free_single_hw_queue(struct blk_mq_hw_ctx *, unsigned int);
 
-void blk_mq_end_io(struct request *rq, int error);
+bool blk_mq_end_io_partial(struct request *rq, int error,
+               unsigned int nr_bytes);
+static inline void blk_mq_end_io(struct request *rq, int error)
+{
+       bool done = !blk_mq_end_io_partial(rq, error, blk_rq_bytes(rq));
+       BUG_ON(!done);
+}
 
 void blk_mq_complete_request(struct request *rq);
 
index dc5f9026b67fb83fdff4129f1bfac0337cc7a595..3ce5e526525f852f37ea242700363036c85068ca 100644 (file)
@@ -33,8 +33,9 @@ enum can_mode {
 struct can_priv {
        struct can_device_stats can_stats;
 
-       struct can_bittiming bittiming;
-       const struct can_bittiming_const *bittiming_const;
+       struct can_bittiming bittiming, data_bittiming;
+       const struct can_bittiming_const *bittiming_const,
+               *data_bittiming_const;
        struct can_clock clock;
 
        enum can_state state;
@@ -45,6 +46,7 @@ struct can_priv {
        struct timer_list restart_timer;
 
        int (*do_set_bittiming)(struct net_device *dev);
+       int (*do_set_data_bittiming)(struct net_device *dev);
        int (*do_set_mode)(struct net_device *dev, enum can_mode mode);
        int (*do_get_state)(const struct net_device *dev,
                            enum can_state *state);
@@ -111,6 +113,7 @@ struct can_priv *safe_candev_priv(struct net_device *dev);
 
 int open_candev(struct net_device *dev);
 void close_candev(struct net_device *dev);
+int can_change_mtu(struct net_device *dev, int new_mtu);
 
 int register_candev(struct net_device *dev);
 void unregister_candev(struct net_device *dev);
index 5c097596104b80535a0a00bdd45b4a2441fac889..9450f025fe0c01ac52bf78caccf114c30312a2e4 100644 (file)
@@ -166,6 +166,8 @@ struct cgroup {
         *
         * The ID of the root cgroup is always 0, and a new cgroup
         * will be assigned with a smallest available ID.
+        *
+        * Allocating/Removing ID must be protected by cgroup_mutex.
         */
        int id;
 
index 092b64168d7fa6935dfe476f1657af9dda620a7a..4a21a872dbbd6423025f1a9253832f228cfe1c48 100644 (file)
@@ -245,6 +245,10 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
 void omap2_init_clk_clkdm(struct clk_hw *clk);
 unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
                                    unsigned long parent_rate);
+int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long parent_rate);
+long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate);
 int omap2_clkops_enable_clkdm(struct clk_hw *hw);
 void omap2_clkops_disable_clkdm(struct clk_hw *hw);
 int omap2_clk_disable_autoidle_all(void);
index cbacf4faf447a9dd2b3fd50d3dc2e4f86a120e67..4d69123377a2b4e0a7869ba38cc91ceb4fd1c7b7 100644 (file)
@@ -28,33 +28,36 @@ static inline void fput_light(struct file *file, int fput_needed)
 
 struct fd {
        struct file *file;
-       int need_put;
+       unsigned int flags;
 };
+#define FDPUT_FPUT       1
+#define FDPUT_POS_UNLOCK 2
 
 static inline void fdput(struct fd fd)
 {
-       if (fd.need_put)
+       if (fd.flags & FDPUT_FPUT)
                fput(fd.file);
 }
 
 extern struct file *fget(unsigned int fd);
-extern struct file *fget_light(unsigned int fd, int *fput_needed);
+extern struct file *fget_raw(unsigned int fd);
+extern unsigned long __fdget(unsigned int fd);
+extern unsigned long __fdget_raw(unsigned int fd);
+extern unsigned long __fdget_pos(unsigned int fd);
 
-static inline struct fd fdget(unsigned int fd)
+static inline struct fd __to_fd(unsigned long v)
 {
-       int b;
-       struct file *f = fget_light(fd, &b);
-       return (struct fd){f,b};
+       return (struct fd){(struct file *)(v & ~3),v & 3};
 }
 
-extern struct file *fget_raw(unsigned int fd);
-extern struct file *fget_raw_light(unsigned int fd, int *fput_needed);
+static inline struct fd fdget(unsigned int fd)
+{
+       return __to_fd(__fdget(fd));
+}
 
 static inline struct fd fdget_raw(unsigned int fd)
 {
-       int b;
-       struct file *f = fget_raw_light(fd, &b);
-       return (struct fd){f,b};
+       return __to_fd(__fdget_raw(fd));
 }
 
 extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
index 5d7782e42b8f22f81df12652348ff9a21aebc7e4..c3683bdf28fe4e677959f33d524bd724a9a1d59d 100644 (file)
@@ -200,6 +200,7 @@ struct fw_device {
        unsigned irmc:1;
        unsigned bc_implemented:2;
 
+       work_func_t workfn;
        struct delayed_work work;
        struct fw_attribute_group attribute_group;
 };
index 60829565e5522a2c68f489665909d39f65230a25..23b2a35d712efbec3e31df0cae70b69a17b81616 100644 (file)
@@ -123,6 +123,9 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 /* File is opened with O_PATH; almost nothing can be done with it */
 #define FMODE_PATH             ((__force fmode_t)0x4000)
 
+/* File needs atomic accesses to f_pos */
+#define FMODE_ATOMIC_POS       ((__force fmode_t)0x8000)
+
 /* File was opened by fanotify and shouldn't generate fanotify events */
 #define FMODE_NONOTIFY         ((__force fmode_t)0x1000000)
 
@@ -780,13 +783,14 @@ struct file {
        const struct file_operations    *f_op;
 
        /*
-        * Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
+        * Protects f_ep_links, f_flags.
         * Must not be taken from IRQ context.
         */
        spinlock_t              f_lock;
        atomic_long_t           f_count;
        unsigned int            f_flags;
        fmode_t                 f_mode;
+       struct mutex            f_pos_lock;
        loff_t                  f_pos;
        struct fown_struct      f_owner;
        const struct cred       *f_cred;
@@ -808,7 +812,7 @@ struct file {
 #ifdef CONFIG_DEBUG_WRITECOUNT
        unsigned long f_mnt_write_state;
 #endif
-};
+} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
 
 struct file_handle {
        __u32 handle_bytes;
index 3d286ff49ab0c82309ec3499bf27cc77f75f3670..64cf3ef50696c7bf50b3c3a3e211cfa9d3accb0d 100644 (file)
@@ -99,7 +99,7 @@ struct fsnotify_ops {
                            struct fsnotify_mark *inode_mark,
                            struct fsnotify_mark *vfsmount_mark,
                            u32 mask, void *data, int data_type,
-                           const unsigned char *file_name);
+                           const unsigned char *file_name, u32 cookie);
        void (*free_group_priv)(struct fsnotify_group *group);
        void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group);
        void (*free_event)(struct fsnotify_event *event);
@@ -160,7 +160,7 @@ struct fsnotify_group {
 
        struct fasync_struct *fsn_fa;    /* async notification */
 
-       struct fsnotify_event overflow_event;   /* Event we queue when the
+       struct fsnotify_event *overflow_event;  /* Event we queue when the
                                                 * notification list is too
                                                 * full */
 
index 0437439bc047bd4a99d7465132b1d9417667934e..39b81dc7d01acdb28e6e888fea3399f7866057f8 100644 (file)
@@ -123,6 +123,10 @@ struct vm_area_struct;
                         __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN | \
                         __GFP_NO_KSWAPD)
 
+/*
+ * GFP_THISNODE does not perform any reclaim, you most likely want to
+ * use __GFP_THISNODE to allocate from a given node without fallback!
+ */
 #ifdef CONFIG_NUMA
 #define GFP_THISNODE   (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
 #else
index db512014e061b27abae7d689175e82d74348683b..b826239bdce0b26a614ae0802782860348dd6fc6 100644 (file)
@@ -157,46 +157,6 @@ static inline int hpage_nr_pages(struct page *page)
                return HPAGE_PMD_NR;
        return 1;
 }
-/*
- * compound_trans_head() should be used instead of compound_head(),
- * whenever the "page" passed as parameter could be the tail of a
- * transparent hugepage that could be undergoing a
- * __split_huge_page_refcount(). The page structure layout often
- * changes across releases and it makes extensive use of unions. So if
- * the page structure layout will change in a way that
- * page->first_page gets clobbered by __split_huge_page_refcount, the
- * implementation making use of smp_rmb() will be required.
- *
- * Currently we define compound_trans_head as compound_head, because
- * page->private is in the same union with page->first_page, and
- * page->private isn't clobbered. However this also means we're
- * currently leaving dirt into the page->private field of anonymous
- * pages resulting from a THP split, instead of setting page->private
- * to zero like for every other page that has PG_private not set. But
- * anonymous pages don't use page->private so this is not a problem.
- */
-#if 0
-/* This will be needed if page->private will be clobbered in split_huge_page */
-static inline struct page *compound_trans_head(struct page *page)
-{
-       if (PageTail(page)) {
-               struct page *head;
-               head = page->first_page;
-               smp_rmb();
-               /*
-                * head may be a dangling pointer.
-                * __split_huge_page_refcount clears PageTail before
-                * overwriting first_page, so if PageTail is still
-                * there it means the head pointer isn't dangling.
-                */
-               if (PageTail(page))
-                       return head;
-       }
-       return page;
-}
-#else
-#define compound_trans_head(page) compound_head(page)
-#endif
 
 extern int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                unsigned long addr, pmd_t pmd, pmd_t *pmdp);
@@ -226,7 +186,6 @@ static inline int split_huge_page(struct page *page)
        do { } while (0)
 #define split_huge_page_pmd_mm(__mm, __address, __pmd) \
        do { } while (0)
-#define compound_trans_head(page) compound_head(page)
 static inline int hugepage_madvise(struct vm_area_struct *vma,
                                   unsigned long *vm_flags, int advice)
 {
index 5f349355ee54d4fda308b55234f743c509a5e207..06299048c4f41dc66ac549b76c4618efccfa73c7 100644 (file)
@@ -2307,42 +2307,6 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr,
        return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC;
 }
 
-/**
- * ieee80211_dsss_chan_to_freq - get channel center frequency
- * @channel: the DSSS channel
- *
- * Convert IEEE802.11 DSSS channel to the center frequency (MHz).
- * Ref IEEE 802.11-2007 section 15.6
- */
-static inline int ieee80211_dsss_chan_to_freq(int channel)
-{
-       if ((channel > 0) && (channel < 14))
-               return 2407 + (channel * 5);
-       else if (channel == 14)
-               return 2484;
-       else
-               return -1;
-}
-
-/**
- * ieee80211_freq_to_dsss_chan - get channel
- * @freq: the frequency
- *
- * Convert frequency (MHz) to IEEE802.11 DSSS channel
- * Ref IEEE 802.11-2007 section 15.6
- *
- * This routine selects the channel with the closest center frequency.
- */
-static inline int ieee80211_freq_to_dsss_chan(int freq)
-{
-       if ((freq >= 2410) && (freq < 2475))
-               return (freq - 2405) / 5;
-       else if ((freq >= 2482) && (freq < 2487))
-               return 14;
-       else
-               return -1;
-}
-
 /**
  * ieee80211_tu_to_usec - convert time units (TU) to microseconds
  * @tu: the TUs
index e7831d20373776f5c3dc80c5a04147e8aa611c85..35e7eca4e33b1fbbde3029b5f3cb2be350d0dafc 100644 (file)
@@ -118,9 +118,7 @@ extern int mq_init_ns(struct ipc_namespace *ns);
  *     the new maximum will handle anyone else.  I may have to revisit this
  *     in the future.
  */
-#define MIN_QUEUESMAX                  1
 #define DFLT_QUEUESMAX               256
-#define HARD_QUEUESMAX              1024
 #define MIN_MSGMAX                     1
 #define DFLT_MSG                      10U
 #define DFLT_MSGMAX                   10
index 5be9f0228a3bbc8ddfad7a2fc245f6601cfc1f17..d267623c28cfdaa385ab5f288683c0157f9e8ef4 100644 (file)
@@ -249,7 +249,8 @@ void kernfs_notify(struct kernfs_node *kn);
 
 const void *kernfs_super_ns(struct super_block *sb);
 struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
-                              struct kernfs_root *root, const void *ns);
+                              struct kernfs_root *root, bool *new_sb_created,
+                              const void *ns);
 void kernfs_kill_sb(struct super_block *sb);
 
 void kernfs_init(void);
@@ -317,7 +318,7 @@ static inline const void *kernfs_super_ns(struct super_block *sb)
 
 static inline struct dentry *
 kernfs_mount_ns(struct file_system_type *fs_type, int flags,
-               struct kernfs_root *root, const void *ns)
+               struct kernfs_root *root, bool *new_sb_created, const void *ns)
 { return ERR_PTR(-ENOSYS); }
 
 static inline void kernfs_kill_sb(struct super_block *sb) { }
@@ -368,9 +369,9 @@ static inline int kernfs_remove_by_name(struct kernfs_node *parent,
 
 static inline struct dentry *
 kernfs_mount(struct file_system_type *fs_type, int flags,
-            struct kernfs_root *root)
+            struct kernfs_root *root, bool *new_sb_created)
 {
-       return kernfs_mount_ns(fs_type, flags, root, NULL);
+       return kernfs_mount_ns(fs_type, flags, root, new_sb_created, NULL);
 }
 
 #endif /* __LINUX_KERNFS_H */
index ad1ae7f345ad9482df4a47c0ddc4ab11bd34e2ec..78c76cd4d37bdff2d1c56e2a9c1c199af6b7a77d 100644 (file)
@@ -387,7 +387,7 @@ struct max8997_dev {
        struct i2c_client *muic; /* slave addr 0x4a */
        struct mutex iolock;
 
-       int type;
+       unsigned long type;
        struct platform_device *battery; /* battery control (not fuel gauge) */
 
        int irq;
index 4ecb24b4b863be4158263466ce919e78b42714d5..d68ada502ff37c1e08164f723db8ef3e33d96a50 100644 (file)
@@ -163,7 +163,7 @@ struct max8998_dev {
        int ono;
        u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS];
        u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS];
-       int type;
+       unsigned long type;
        bool wakeup;
 };
 
index a5a7f0130e9604837982d4b2f3bb9920fd5d090c..54b5458ec084a50ec06cc9f418d4e623e0aaf7bc 100644 (file)
@@ -252,7 +252,7 @@ struct tps65217_board {
 struct tps65217 {
        struct device *dev;
        struct tps65217_board *pdata;
-       unsigned int id;
+       unsigned long id;
        struct regulator_desc desc[TPS65217_NUM_REGULATOR];
        struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
        struct regmap *regmap;
@@ -263,7 +263,7 @@ static inline struct tps65217 *dev_to_tps65217(struct device *dev)
        return dev_get_drvdata(dev);
 }
 
-static inline int tps65217_chip_id(struct tps65217 *tps65217)
+static inline unsigned long tps65217_chip_id(struct tps65217 *tps65217)
 {
        return tps65217->id;
 }
index 3737f7218f51362ea9cf1991a66c0328143741b8..7bb6148d990fbdd89303d6edd5e5491c02095f39 100644 (file)
@@ -23,6 +23,7 @@
 #define TEMP_MINOR             131     /* Temperature Sensor */
 #define RTC_MINOR              135
 #define EFI_RTC_MINOR          136     /* EFI Time services */
+#define VHCI_MINOR             137
 #define SUN_OPENPROM_MINOR     139
 #define DMAPI_MINOR            140     /* DMAPI */
 #define NVRAM_MINOR            144
index 79a34723816895e59c794872f94d03893920c15b..009985628257590ebf90bea810b57c2767b375e0 100644 (file)
@@ -240,6 +240,13 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos);
 int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting);
 int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf);
 int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state);
+/*
+ * mlx4_get_slave_default_vlan -
+ * return true if VST ( default vlan)
+ * if VST, will return vlan & qos (if not NULL)
+ */
+bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave,
+                                u16 *vlan, u8 *qos);
 
 #define MLX4_COMM_GET_IF_REV(cmd_chan_ver) (u8)((cmd_chan_ver) >> 8)
 
index 5edd2c68274dd449f34f557296ce789e38578dad..f211b51dc726bf06daef5c16697d79bee7737a35 100644 (file)
@@ -48,6 +48,9 @@
 #define MSIX_LEGACY_SZ         4
 #define MIN_MSIX_P_PORT                5
 
+#define MLX4_ROCE_MAX_GIDS     128
+#define MLX4_ROCE_PF_GIDS      16
+
 enum {
        MLX4_FLAG_MSI_X         = 1 << 0,
        MLX4_FLAG_OLD_PORT_CMDS = 1 << 1,
@@ -629,7 +632,8 @@ struct mlx4_eth_av {
        u8              hop_limit;
        __be32          sl_tclass_flowlabel;
        u8              dgid[16];
-       u32             reserved4[2];
+       u8              s_mac[6];
+       u8              reserved4[2];
        __be16          vlan;
        u8              mac[ETH_ALEN];
 };
@@ -1183,6 +1187,11 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, int
 void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid);
 __be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave);
 
+int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
+                                int *slave_id);
+int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
+                                u8 *gid);
+
 int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn,
                                      u32 max_range_qpn);
 
index f28f46eade6a642873246fea247f3f5455a18acb..c1b7414c7bef7c0a2128edd30438e48974af40f3 100644 (file)
@@ -175,7 +175,7 @@ extern unsigned int kobjsize(const void *objp);
  * Special vmas that are non-mergable, non-mlock()able.
  * Note: mm/huge_memory.c VM_NO_THP depends on this definition.
  */
-#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP)
+#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP)
 
 /*
  * mapping from the currently active vm_flags protection bits (the
@@ -399,8 +399,18 @@ static inline void compound_unlock_irqrestore(struct page *page,
 
 static inline struct page *compound_head(struct page *page)
 {
-       if (unlikely(PageTail(page)))
-               return page->first_page;
+       if (unlikely(PageTail(page))) {
+               struct page *head = page->first_page;
+
+               /*
+                * page->first_page may be a dangling pointer to an old
+                * compound page, so recheck that it is still a tail
+                * page before returning.
+                */
+               smp_rmb();
+               if (likely(PageTail(page)))
+                       return head;
+       }
        return page;
 }
 
@@ -757,7 +767,7 @@ static inline bool __cpupid_match_pid(pid_t task_pid, int cpupid)
 #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
 static inline int page_cpupid_xchg_last(struct page *page, int cpupid)
 {
-       return xchg(&page->_last_cpupid, cpupid);
+       return xchg(&page->_last_cpupid, cpupid & LAST_CPUPID_MASK);
 }
 
 static inline int page_cpupid_last(struct page *page)
@@ -766,7 +776,7 @@ static inline int page_cpupid_last(struct page *page)
 }
 static inline void page_cpupid_reset_last(struct page *page)
 {
-       page->_last_cpupid = -1;
+       page->_last_cpupid = -1 & LAST_CPUPID_MASK;
 }
 #else
 static inline int page_cpupid_last(struct page *page)
index 5f2052c831547a33b66606d78ac5713086d285e3..9b61b9bf81ac86a90c1ce70d12400b745b7582eb 100644 (file)
@@ -590,10 +590,10 @@ static inline bool zone_is_empty(struct zone *zone)
 
 /*
  * The NUMA zonelists are doubled because we need zonelists that restrict the
- * allocations to a single node for GFP_THISNODE.
+ * allocations to a single node for __GFP_THISNODE.
  *
  * [0] : Zonelist with fallback
- * [1] : No fallback (GFP_THISNODE)
+ * [1] : No fallback (__GFP_THISNODE)
  */
 #define MAX_ZONELISTS 2
 
index 1a869488b8aece23124588b24e2e33294142738f..4b6d12c7b803b7955848fa9309d725ba09da4d79 100644 (file)
@@ -1812,7 +1812,7 @@ struct pcpu_sw_netstats {
 
 #define netdev_alloc_pcpu_stats(type)                          \
 ({                                                             \
-       typeof(type) *pcpu_stats = alloc_percpu(type);          \
+       typeof(type) __percpu *pcpu_stats = alloc_percpu(type); \
        if (pcpu_stats) {                                       \
                int i;                                          \
                for_each_possible_cpu(i) {                      \
@@ -1979,9 +1979,6 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex);
 struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
 int netdev_get_name(struct net *net, char *name, int ifindex);
 int dev_restart(struct net_device *dev);
-#ifdef CONFIG_NETPOLL_TRAP
-int netpoll_trap(void);
-#endif
 int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb);
 
 static inline unsigned int skb_gro_offset(const struct sk_buff *skb)
@@ -2186,12 +2183,6 @@ static inline void netif_tx_start_all_queues(struct net_device *dev)
 
 static inline void netif_tx_wake_queue(struct netdev_queue *dev_queue)
 {
-#ifdef CONFIG_NETPOLL_TRAP
-       if (netpoll_trap()) {
-               netif_tx_start_queue(dev_queue);
-               return;
-       }
-#endif
        if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state))
                __netif_schedule(dev_queue->qdisc);
 }
@@ -2435,10 +2426,6 @@ static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index)
 static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index)
 {
        struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index);
-#ifdef CONFIG_NETPOLL_TRAP
-       if (netpoll_trap())
-               return;
-#endif
        netif_tx_stop_queue(txq);
 }
 
@@ -2473,10 +2460,6 @@ static inline bool netif_subqueue_stopped(const struct net_device *dev,
 static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index)
 {
        struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index);
-#ifdef CONFIG_NETPOLL_TRAP
-       if (netpoll_trap())
-               return;
-#endif
        if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &txq->state))
                __netif_schedule(txq->qdisc);
 }
index 0c7d01eae56cf8626d2d1fc55242b3cbae0ba1ad..96afc29184bee810a1ec550933cfb15998f42efb 100644 (file)
@@ -39,11 +39,13 @@ enum ip_set_feature {
        IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
        IPSET_TYPE_IFACE_FLAG = 5,
        IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG),
-       IPSET_TYPE_NOMATCH_FLAG = 6,
+       IPSET_TYPE_MARK_FLAG = 6,
+       IPSET_TYPE_MARK = (1 << IPSET_TYPE_MARK_FLAG),
+       IPSET_TYPE_NOMATCH_FLAG = 7,
        IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG),
        /* Strictly speaking not a feature, but a flag for dumping:
         * this settype must be dumped last */
-       IPSET_DUMP_LAST_FLAG = 7,
+       IPSET_DUMP_LAST_FLAG = 8,
        IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
 };
 
@@ -63,6 +65,7 @@ enum ip_set_extension {
 #define SET_WITH_TIMEOUT(s)    ((s)->extensions & IPSET_EXT_TIMEOUT)
 #define SET_WITH_COUNTER(s)    ((s)->extensions & IPSET_EXT_COUNTER)
 #define SET_WITH_COMMENT(s)    ((s)->extensions & IPSET_EXT_COMMENT)
+#define SET_WITH_FORCEADD(s)   ((s)->flags & IPSET_CREATE_FLAG_FORCEADD)
 
 /* Extension id, in size order */
 enum ip_set_ext_id {
@@ -171,8 +174,6 @@ struct ip_set_type {
        char name[IPSET_MAXNAMELEN];
        /* Protocol version */
        u8 protocol;
-       /* Set features to control swapping */
-       u8 features;
        /* Set type dimension */
        u8 dimension;
        /*
@@ -182,6 +183,8 @@ struct ip_set_type {
        u8 family;
        /* Type revisions */
        u8 revision_min, revision_max;
+       /* Set features to control swapping */
+       u16 features;
 
        /* Create set */
        int (*create)(struct net *net, struct ip_set *set,
@@ -217,6 +220,8 @@ struct ip_set {
        u8 revision;
        /* Extensions */
        u8 extensions;
+       /* Create flags */
+       u8 flags;
        /* Default timeout value, if enabled */
        u32 timeout;
        /* Element data size */
@@ -251,6 +256,8 @@ ip_set_put_flags(struct sk_buff *skb, struct ip_set *set)
                cadt_flags |= IPSET_FLAG_WITH_COUNTERS;
        if (SET_WITH_COMMENT(set))
                cadt_flags |= IPSET_FLAG_WITH_COMMENT;
+       if (SET_WITH_FORCEADD(set))
+               cadt_flags |= IPSET_FLAG_WITH_FORCEADD;
 
        if (!cadt_flags)
                return 0;
index 28c74367e900ac679aa5feba98b7629ea6338af3..e955d47306259c5867d80831bd78d99490849b0b 100644 (file)
@@ -44,6 +44,27 @@ int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
 
 void nfnl_lock(__u8 subsys_id);
 void nfnl_unlock(__u8 subsys_id);
+#ifdef CONFIG_PROVE_LOCKING
+int lockdep_nfnl_is_held(__u8 subsys_id);
+#else
+static inline int lockdep_nfnl_is_held(__u8 subsys_id)
+{
+       return 1;
+}
+#endif /* CONFIG_PROVE_LOCKING */
+
+/*
+ * nfnl_dereference - fetch RCU pointer when updates are prevented by subsys mutex
+ *
+ * @p: The pointer to read, prior to dereferencing
+ * @ss: The nfnetlink subsystem ID
+ *
+ * Return the value of the specified RCU-protected pointer, but omit
+ * both the smp_read_barrier_depends() and the ACCESS_ONCE(), because
+ * caller holds the NFNL subsystem mutex.
+ */
+#define nfnl_dereference(p, ss)                                        \
+       rcu_dereference_protected(p, lockdep_nfnl_is_held(ss))
 
 #define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
        MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
index fbfdb9d8d3a7f59b4788bdfd1cdb26c86f0a81ca..1b475a5a72393e8e4f600da1a36073ed845d6bb5 100644 (file)
@@ -24,27 +24,20 @@ struct netpoll {
        struct net_device *dev;
        char dev_name[IFNAMSIZ];
        const char *name;
-       void (*rx_skb_hook)(struct netpoll *np, int source, struct sk_buff *skb,
-                           int offset, int len);
 
        union inet_addr local_ip, remote_ip;
        bool ipv6;
        u16 local_port, remote_port;
        u8 remote_mac[ETH_ALEN];
 
-       struct list_head rx; /* rx_np list element */
        struct work_struct cleanup_work;
 };
 
 struct netpoll_info {
        atomic_t refcnt;
 
-       unsigned long rx_flags;
-       spinlock_t rx_lock;
        struct semaphore dev_lock;
-       struct list_head rx_np; /* netpolls that registered an rx_skb_hook */
 
-       struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */
        struct sk_buff_head txq;
 
        struct delayed_work tx_work;
@@ -66,12 +59,9 @@ void netpoll_print_options(struct netpoll *np);
 int netpoll_parse_options(struct netpoll *np, char *opt);
 int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp);
 int netpoll_setup(struct netpoll *np);
-int netpoll_trap(void);
-void netpoll_set_trap(int trap);
 void __netpoll_cleanup(struct netpoll *np);
 void __netpoll_free_async(struct netpoll *np);
 void netpoll_cleanup(struct netpoll *np);
-int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo);
 void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
                             struct net_device *dev);
 static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
@@ -82,46 +72,7 @@ static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
        local_irq_restore(flags);
 }
 
-
-
 #ifdef CONFIG_NETPOLL
-static inline bool netpoll_rx_on(struct sk_buff *skb)
-{
-       struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
-
-       return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
-}
-
-static inline bool netpoll_rx(struct sk_buff *skb)
-{
-       struct netpoll_info *npinfo;
-       unsigned long flags;
-       bool ret = false;
-
-       local_irq_save(flags);
-
-       if (!netpoll_rx_on(skb))
-               goto out;
-
-       npinfo = rcu_dereference_bh(skb->dev->npinfo);
-       spin_lock(&npinfo->rx_lock);
-       /* check rx_flags again with the lock held */
-       if (npinfo->rx_flags && __netpoll_rx(skb, npinfo))
-               ret = true;
-       spin_unlock(&npinfo->rx_lock);
-
-out:
-       local_irq_restore(flags);
-       return ret;
-}
-
-static inline int netpoll_receive_skb(struct sk_buff *skb)
-{
-       if (!list_empty(&skb->dev->napi_list))
-               return netpoll_rx(skb);
-       return 0;
-}
-
 static inline void *netpoll_poll_lock(struct napi_struct *napi)
 {
        struct net_device *dev = napi->dev;
@@ -150,18 +101,6 @@ static inline bool netpoll_tx_running(struct net_device *dev)
 }
 
 #else
-static inline bool netpoll_rx(struct sk_buff *skb)
-{
-       return false;
-}
-static inline bool netpoll_rx_on(struct sk_buff *skb)
-{
-       return false;
-}
-static inline int netpoll_receive_skb(struct sk_buff *skb)
-{
-       return 0;
-}
 static inline void *netpoll_poll_lock(struct napi_struct *napi)
 {
        return NULL;
index b2fb167b2e6d99ed71a1ab6ddeae6c7c3885600a..5624e4e2763c2eb3d73f4e02d2752661ccd9c6b9 100644 (file)
@@ -467,9 +467,14 @@ struct nfs_lockt_res {
 };
 
 struct nfs_release_lockowner_args {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_lowner       lock_owner;
 };
 
+struct nfs_release_lockowner_res {
+       struct nfs4_sequence_res        seq_res;
+};
+
 struct nfs4_delegreturnargs {
        struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *fhandle;
index fb57c892b214d6b3482c63a28061130f3a700a9c..33aa2caf0f0c9e5bd9e7cf07c8d92b08207be959 100644 (file)
@@ -1169,8 +1169,23 @@ void msi_remove_pci_irq_vectors(struct pci_dev *dev);
 void pci_restore_msi_state(struct pci_dev *dev);
 int pci_msi_enabled(void);
 int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec);
+static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+{
+       int rc = pci_enable_msi_range(dev, nvec, nvec);
+       if (rc < 0)
+               return rc;
+       return 0;
+}
 int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
                          int minvec, int maxvec);
+static inline int pci_enable_msix_exact(struct pci_dev *dev,
+                                       struct msix_entry *entries, int nvec)
+{
+       int rc = pci_enable_msix_range(dev, entries, nvec, nvec);
+       if (rc < 0)
+               return rc;
+       return 0;
+}
 #else
 static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
 static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec)
@@ -1189,9 +1204,14 @@ static inline int pci_msi_enabled(void) { return 0; }
 static inline int pci_enable_msi_range(struct pci_dev *dev, int minvec,
                                       int maxvec)
 { return -ENOSYS; }
+static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+{ return -ENOSYS; }
 static inline int pci_enable_msix_range(struct pci_dev *dev,
                      struct msix_entry *entries, int minvec, int maxvec)
 { return -ENOSYS; }
+static inline int pci_enable_msix_exact(struct pci_dev *dev,
+                     struct msix_entry *entries, int nvec)
+{ return -ENOSYS; }
 #endif
 
 #ifdef CONFIG_PCIEPORTBUS
index 6d8ed22accb480a9a26249c4d2e2f1b078440fa2..03db95ab8a8cdeea706b37ce2654442230952388 100644 (file)
@@ -2782,7 +2782,7 @@ static inline void nf_reset(struct sk_buff *skb)
 
 static inline void nf_reset_trace(struct sk_buff *skb)
 {
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
        skb->nf_trace = 0;
 #endif
 }
@@ -2799,6 +2799,9 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
        dst->nf_bridge  = src->nf_bridge;
        nf_bridge_get(src->nf_bridge);
 #endif
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
+       dst->nf_trace = src->nf_trace;
+#endif
 }
 
 static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
index 9260abdd67df801e002f18faf3f17bd00d494867..b5b2df60299e25c5c33b3be39ff90090c974689f 100644 (file)
@@ -410,7 +410,7 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
  *
  * %GFP_NOWAIT - Allocation will not sleep.
  *
- * %GFP_THISNODE - Allocate node-local memory only.
+ * %__GFP_THISNODE - Allocate node-local memory only.
  *
  * %GFP_DMA - Allocation suitable for DMA.
  *   Should only be used for kmalloc() caches. Otherwise, use a
index 40ed9e9a77e53c77448104a921c0595f2a7927eb..a747a77ea584aafb124ae230862360c8dd0b6073 100644 (file)
@@ -281,13 +281,15 @@ asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
 asmlinkage long sys_sched_setparam(pid_t pid,
                                        struct sched_param __user *param);
 asmlinkage long sys_sched_setattr(pid_t pid,
-                                       struct sched_attr __user *attr);
+                                       struct sched_attr __user *attr,
+                                       unsigned int flags);
 asmlinkage long sys_sched_getscheduler(pid_t pid);
 asmlinkage long sys_sched_getparam(pid_t pid,
                                        struct sched_param __user *param);
 asmlinkage long sys_sched_getattr(pid_t pid,
                                        struct sched_attr __user *attr,
-                                       unsigned int size);
+                                       unsigned int size,
+                                       unsigned int flags);
 asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len,
                                        unsigned long __user *user_mask_ptr);
 asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len,
index accc497f8d729160b0234756e96d99607cf67f33..7159a0a933df2b016db23cdcd87487c19d5829d0 100644 (file)
@@ -60,6 +60,12 @@ struct tp_module {
        unsigned int num_tracepoints;
        struct tracepoint * const *tracepoints_ptrs;
 };
+bool trace_module_has_bad_taint(struct module *mod);
+#else
+static inline bool trace_module_has_bad_taint(struct module *mod)
+{
+       return false;
+}
 #endif /* CONFIG_MODULES */
 
 struct tracepoint_iter {
index 90b4fdc8a61f14fcd8753bc5d7d55d89924e9302..4781d7b27dd39d9930164592d008aa1ac22772c3 100644 (file)
@@ -518,9 +518,9 @@ extern void tty_port_put(struct tty_port *port);
 
 static inline struct tty_port *tty_port_get(struct tty_port *port)
 {
-       if (port)
-               kref_get(&port->kref);
-       return port;
+       if (port && kref_get_unless_zero(&port->kref))
+               return port;
+       return NULL;
 }
 
 /* If the cts flow control is enabled, return true. */
index 7bfabd20204c150afa40a7249932519c0e770267..4b4439e75f45f8e915f0ffb6b855be5f1113a04f 100644 (file)
@@ -27,8 +27,8 @@
  *    (On UP, there is no seqcount_t protection, a reader allowing interrupts could
  *     read partial values)
  *
- * 7) For softirq uses, readers can use u64_stats_fetch_begin_bh() and
- *    u64_stats_fetch_retry_bh() helpers
+ * 7) For irq and softirq uses, readers can use u64_stats_fetch_begin_irq() and
+ *    u64_stats_fetch_retry_irq() helpers
  *
  * Usage :
  *
@@ -114,31 +114,31 @@ static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp,
 }
 
 /*
- * In case softirq handlers can update u64 counters, readers can use following helpers
+ * In case irq handlers can update u64 counters, readers can use following helpers
  * - SMP 32bit arches use seqcount protection, irq safe.
- * - UP 32bit must disable BH.
+ * - UP 32bit must disable irqs.
  * - 64bit have no problem atomically reading u64 values, irq safe.
  */
-static inline unsigned int u64_stats_fetch_begin_bh(const struct u64_stats_sync *syncp)
+static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *syncp)
 {
 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
        return read_seqcount_begin(&syncp->seq);
 #else
 #if BITS_PER_LONG==32
-       local_bh_disable();
+       local_irq_disable();
 #endif
        return 0;
 #endif
 }
 
-static inline bool u64_stats_fetch_retry_bh(const struct u64_stats_sync *syncp,
+static inline bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *syncp,
                                         unsigned int start)
 {
 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
        return read_seqcount_retry(&syncp->seq, start);
 #else
 #if BITS_PER_LONG==32
-       local_bh_enable();
+       local_irq_enable();
 #endif
        return false;
 #endif
index a54fe82e704bc09c5acd6a5f1664a6dfbc982b64..a9c723be1acfca6cd6d6bbfa37f453404aadb83d 100644 (file)
@@ -48,11 +48,15 @@ enum {
        WL12XX_TCXOCLOCK_33_6   = 7, /* 33.6 MHz */
 };
 
-struct wl12xx_platform_data {
-       void (*set_power)(bool enable);
+struct wl1251_platform_data {
+       int power_gpio;
        /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */
        int irq;
        bool use_eeprom;
+};
+
+struct wl12xx_platform_data {
+       int irq;
        int board_ref_clock;
        int board_tcxo_clock;
        unsigned long platform_quirks;
@@ -68,6 +72,10 @@ int wl12xx_set_platform_data(const struct wl12xx_platform_data *data);
 
 struct wl12xx_platform_data *wl12xx_get_platform_data(void);
 
+int wl1251_set_platform_data(const struct wl1251_platform_data *data);
+
+struct wl1251_platform_data *wl1251_get_platform_data(void);
+
 #else
 
 static inline
@@ -82,6 +90,18 @@ struct wl12xx_platform_data *wl12xx_get_platform_data(void)
        return ERR_PTR(-ENODATA);
 }
 
+static inline
+int wl1251_set_platform_data(const struct wl1251_platform_data *data)
+{
+       return -ENOSYS;
+}
+
+static inline
+struct wl1251_platform_data *wl1251_get_platform_data(void)
+{
+       return ERR_PTR(-ENODATA);
+}
+
 #endif
 
 #endif
index 594521ba0d43f73e887375968006429c9ec19502..704f4f652d0af8b28406154678ee38b5f98298bf 100644 (file)
@@ -419,10 +419,7 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
        static struct lock_class_key __key;                             \
        const char *__lock_name;                                        \
                                                                        \
-       if (__builtin_constant_p(fmt))                                  \
-               __lock_name = (fmt);                                    \
-       else                                                            \
-               __lock_name = #fmt;                                     \
+       __lock_name = #fmt#args;                                        \
                                                                        \
        __alloc_workqueue_key((fmt), (flags), (max_active),             \
                              &__key, __lock_name, ##args);             \
index fc0e4320aa6d50d0e5f966e3f8b649506d461ac7..021b8a319b9e2cf7f0f60a5f6fedcfe3367f8016 100644 (file)
@@ -97,7 +97,7 @@ void writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
 int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason);
 int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
                                  enum wb_reason reason);
-void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this);
+void sync_inodes_sb(struct super_block *);
 void wakeup_flusher_threads(long nr_pages, enum wb_reason reason);
 void inode_wait_for_writeback(struct inode *inode);
 
diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
new file mode 100644 (file)
index 0000000..f7d372b
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * 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.
+ */
+
+#ifndef __6LOWPAN_H__
+#define __6LOWPAN_H__
+
+#include <net/ipv6.h>
+
+#define UIP_802154_SHORTADDR_LEN       2  /* compressed ipv6 address length */
+#define UIP_IPH_LEN                    40 /* ipv6 fixed header size */
+#define UIP_PROTO_UDP                  17 /* ipv6 next header value for UDP */
+#define UIP_FRAGH_LEN                  8  /* ipv6 fragment header size */
+
+/*
+ * ipv6 address based on mac
+ * second bit-flip (Universe/Local) is done according RFC2464
+ */
+#define is_addr_mac_addr_based(a, m) \
+       ((((a)->s6_addr[8])  == (((m)[0]) ^ 0x02)) &&   \
+        (((a)->s6_addr[9])  == (m)[1]) &&              \
+        (((a)->s6_addr[10]) == (m)[2]) &&              \
+        (((a)->s6_addr[11]) == (m)[3]) &&              \
+        (((a)->s6_addr[12]) == (m)[4]) &&              \
+        (((a)->s6_addr[13]) == (m)[5]) &&              \
+        (((a)->s6_addr[14]) == (m)[6]) &&              \
+        (((a)->s6_addr[15]) == (m)[7]))
+
+/* ipv6 address is unspecified */
+#define is_addr_unspecified(a)         \
+       ((((a)->s6_addr32[0]) == 0) &&  \
+        (((a)->s6_addr32[1]) == 0) &&  \
+        (((a)->s6_addr32[2]) == 0) &&  \
+        (((a)->s6_addr32[3]) == 0))
+
+/* compare ipv6 addresses prefixes */
+#define ipaddr_prefixcmp(addr1, addr2, length) \
+       (memcmp(addr1, addr2, length >> 3) == 0)
+
+/* local link, i.e. FE80::/10 */
+#define is_addr_link_local(a) (((a)->s6_addr16[0]) == htons(0xFE80))
+
+/*
+ * check whether we can compress the IID to 16 bits,
+ * it's possible for unicast adresses with first 49 bits are zero only.
+ */
+#define lowpan_is_iid_16_bit_compressable(a)   \
+       ((((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr[10]) == 0) &&           \
+        (((a)->s6_addr[11]) == 0xff) &&        \
+        (((a)->s6_addr[12]) == 0xfe) &&        \
+        (((a)->s6_addr[13]) == 0))
+
+/* multicast address */
+#define is_addr_mcast(a) (((a)->s6_addr[0]) == 0xFF)
+
+/* check whether the 112-bit gid of the multicast address is mappable to: */
+
+/* 9 bits, for FF02::1 (all nodes) and FF02::2 (all routers) addresses only. */
+#define lowpan_is_mcast_addr_compressable(a)   \
+       ((((a)->s6_addr16[1]) == 0) &&          \
+        (((a)->s6_addr16[2]) == 0) &&          \
+        (((a)->s6_addr16[3]) == 0) &&          \
+        (((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr16[5]) == 0) &&          \
+        (((a)->s6_addr16[6]) == 0) &&          \
+        (((a)->s6_addr[14])  == 0) &&          \
+        ((((a)->s6_addr[15]) == 1) || (((a)->s6_addr[15]) == 2)))
+
+/* 48 bits, FFXX::00XX:XXXX:XXXX */
+#define lowpan_is_mcast_addr_compressable48(a) \
+       ((((a)->s6_addr16[1]) == 0) &&          \
+        (((a)->s6_addr16[2]) == 0) &&          \
+        (((a)->s6_addr16[3]) == 0) &&          \
+        (((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr[10]) == 0))
+
+/* 32 bits, FFXX::00XX:XXXX */
+#define lowpan_is_mcast_addr_compressable32(a) \
+       ((((a)->s6_addr16[1]) == 0) &&          \
+        (((a)->s6_addr16[2]) == 0) &&          \
+        (((a)->s6_addr16[3]) == 0) &&          \
+        (((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr16[5]) == 0) &&          \
+        (((a)->s6_addr[12]) == 0))
+
+/* 8 bits, FF02::00XX */
+#define lowpan_is_mcast_addr_compressable8(a)  \
+       ((((a)->s6_addr[1])  == 2) &&           \
+        (((a)->s6_addr16[1]) == 0) &&          \
+        (((a)->s6_addr16[2]) == 0) &&          \
+        (((a)->s6_addr16[3]) == 0) &&          \
+        (((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr16[5]) == 0) &&          \
+        (((a)->s6_addr16[6]) == 0) &&          \
+        (((a)->s6_addr[14]) == 0))
+
+#define lowpan_is_addr_broadcast(a)    \
+       ((((a)[0]) == 0xFF) &&  \
+        (((a)[1]) == 0xFF) &&  \
+        (((a)[2]) == 0xFF) &&  \
+        (((a)[3]) == 0xFF) &&  \
+        (((a)[4]) == 0xFF) &&  \
+        (((a)[5]) == 0xFF) &&  \
+        (((a)[6]) == 0xFF) &&  \
+        (((a)[7]) == 0xFF))
+
+#define LOWPAN_DISPATCH_IPV6   0x41 /* 01000001 = 65 */
+#define LOWPAN_DISPATCH_HC1    0x42 /* 01000010 = 66 */
+#define LOWPAN_DISPATCH_IPHC   0x60 /* 011xxxxx = ... */
+#define LOWPAN_DISPATCH_FRAG1  0xc0 /* 11000xxx */
+#define LOWPAN_DISPATCH_FRAGN  0xe0 /* 11100xxx */
+
+#define LOWPAN_DISPATCH_MASK   0xf8 /* 11111000 */
+
+#define LOWPAN_FRAG_TIMEOUT    (HZ * 60)       /* time-out 60 sec */
+
+#define LOWPAN_FRAG1_HEAD_SIZE 0x4
+#define LOWPAN_FRAGN_HEAD_SIZE 0x5
+
+/*
+ * According IEEE802.15.4 standard:
+ *   - MTU is 127 octets
+ *   - maximum MHR size is 37 octets
+ *   - MFR size is 2 octets
+ *
+ * so minimal payload size that we may guarantee is:
+ *   MTU - MHR - MFR = 88 octets
+ */
+#define LOWPAN_FRAG_SIZE       88
+
+/*
+ * Values of fields within the IPHC encoding first byte
+ * (C stands for compressed and I for inline)
+ */
+#define LOWPAN_IPHC_TF         0x18
+
+#define LOWPAN_IPHC_FL_C       0x10
+#define LOWPAN_IPHC_TC_C       0x08
+#define LOWPAN_IPHC_NH_C       0x04
+#define LOWPAN_IPHC_TTL_1      0x01
+#define LOWPAN_IPHC_TTL_64     0x02
+#define LOWPAN_IPHC_TTL_255    0x03
+#define LOWPAN_IPHC_TTL_I      0x00
+
+
+/* Values of fields within the IPHC encoding second byte */
+#define LOWPAN_IPHC_CID                0x80
+
+#define LOWPAN_IPHC_ADDR_00    0x00
+#define LOWPAN_IPHC_ADDR_01    0x01
+#define LOWPAN_IPHC_ADDR_02    0x02
+#define LOWPAN_IPHC_ADDR_03    0x03
+
+#define LOWPAN_IPHC_SAC                0x40
+#define LOWPAN_IPHC_SAM                0x30
+
+#define LOWPAN_IPHC_SAM_BIT    4
+
+#define LOWPAN_IPHC_M          0x08
+#define LOWPAN_IPHC_DAC                0x04
+#define LOWPAN_IPHC_DAM_00     0x00
+#define LOWPAN_IPHC_DAM_01     0x01
+#define LOWPAN_IPHC_DAM_10     0x02
+#define LOWPAN_IPHC_DAM_11     0x03
+
+#define LOWPAN_IPHC_DAM_BIT    0
+/*
+ * LOWPAN_UDP encoding (works together with IPHC)
+ */
+#define LOWPAN_NHC_UDP_MASK            0xF8
+#define LOWPAN_NHC_UDP_ID              0xF0
+#define LOWPAN_NHC_UDP_CHECKSUMC       0x04
+#define LOWPAN_NHC_UDP_CHECKSUMI       0x00
+
+#define LOWPAN_NHC_UDP_4BIT_PORT       0xF0B0
+#define LOWPAN_NHC_UDP_4BIT_MASK       0xFFF0
+#define LOWPAN_NHC_UDP_8BIT_PORT       0xF000
+#define LOWPAN_NHC_UDP_8BIT_MASK       0xFF00
+
+/* values for port compression, _with checksum_ ie bit 5 set to 0 */
+#define LOWPAN_NHC_UDP_CS_P_00 0xF0 /* all inline */
+#define LOWPAN_NHC_UDP_CS_P_01 0xF1 /* source 16bit inline,
+                                       dest = 0xF0 + 8 bit inline */
+#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)
+{
+       if (unlikely(!pskb_may_pull(skb, len)))
+               return true;
+
+       skb_copy_from_linear_data(skb, data, len);
+       skb_pull(skb, len);
+
+       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;
+}
+
+static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
+{
+       static const u8 addr_sizes[] = {
+               [LOWPAN_IPHC_ADDR_00] = 16,
+               [LOWPAN_IPHC_ADDR_01] = 8,
+               [LOWPAN_IPHC_ADDR_02] = 2,
+               [LOWPAN_IPHC_ADDR_03] = 0,
+       };
+       return addr_sizes[addr_mode];
+}
+
+static inline u8 lowpan_next_hdr_size(const u8 h_enc, u16 *uncomp_header)
+{
+       u8 ret = 1;
+
+       if ((h_enc & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
+               *uncomp_header += sizeof(struct udphdr);
+
+               switch (h_enc & LOWPAN_NHC_UDP_CS_P_11) {
+               case LOWPAN_NHC_UDP_CS_P_00:
+                       ret += 4;
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_01:
+               case LOWPAN_NHC_UDP_CS_P_10:
+                       ret += 3;
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_11:
+                       ret++;
+                       break;
+               default:
+                       break;
+               }
+
+               if (!(h_enc & LOWPAN_NHC_UDP_CS_C))
+                       ret += 2;
+       }
+
+       return ret;
+}
+
+/**
+ *     lowpan_uncompress_size - returns skb->len size with uncompressed header
+ *     @skb: sk_buff with 6lowpan header inside
+ *     @datagram_offset: optional to get the datagram_offset value
+ *
+ *     Returns the skb->len with uncompressed header
+ */
+static inline u16
+lowpan_uncompress_size(const struct sk_buff *skb, u16 *dgram_offset)
+{
+       u16 ret = 2, uncomp_header = sizeof(struct ipv6hdr);
+       u8 iphc0, iphc1, h_enc;
+
+       iphc0 = skb_network_header(skb)[0];
+       iphc1 = skb_network_header(skb)[1];
+
+       switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
+       case 0:
+               ret += 4;
+               break;
+       case 1:
+               ret += 3;
+               break;
+       case 2:
+               ret++;
+               break;
+       default:
+               break;
+       }
+
+       if (!(iphc0 & LOWPAN_IPHC_NH_C))
+               ret++;
+
+       if (!(iphc0 & 0x03))
+               ret++;
+
+       ret += lowpan_addr_mode_size((iphc1 & LOWPAN_IPHC_SAM) >>
+                                    LOWPAN_IPHC_SAM_BIT);
+
+       if (iphc1 & LOWPAN_IPHC_M) {
+               switch ((iphc1 & LOWPAN_IPHC_DAM_11) >>
+                       LOWPAN_IPHC_DAM_BIT) {
+               case LOWPAN_IPHC_DAM_00:
+                       ret += 16;
+                       break;
+               case LOWPAN_IPHC_DAM_01:
+                       ret += 6;
+                       break;
+               case LOWPAN_IPHC_DAM_10:
+                       ret += 4;
+                       break;
+               case LOWPAN_IPHC_DAM_11:
+                       ret++;
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               ret += lowpan_addr_mode_size((iphc1 & LOWPAN_IPHC_DAM_11) >>
+                                            LOWPAN_IPHC_DAM_BIT);
+       }
+
+       if (iphc0 & LOWPAN_IPHC_NH_C) {
+               h_enc = skb_network_header(skb)[ret];
+               ret += lowpan_next_hdr_size(h_enc, &uncomp_header);
+       }
+
+       if (dgram_offset)
+               *dgram_offset = uncomp_header;
+
+       return skb->len + uncomp_header - ret;
+}
+
+typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev);
+
+int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
+               const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
+               const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
+               u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver);
+int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
+                       unsigned short type, const void *_daddr,
+                       const void *_saddr, unsigned int len);
+
+#endif /* __6LOWPAN_H__ */
index 75e64c7a2960a17a0f3c7f6ce62553c6c874f0c9..f79ae2aa76d6a45fb9a1e452d53f82d05e101717 100644 (file)
@@ -36,7 +36,7 @@ enum {
 /* address length, octets */
 #define IEEE802154_ADDR_LEN    8
 
-struct ieee802154_addr {
+struct ieee802154_addr_sa {
        int addr_type;
        u16 pan_id;
        union {
@@ -51,7 +51,7 @@ struct ieee802154_addr {
 
 struct sockaddr_ieee802154 {
        sa_family_t family; /* AF_IEEE802154 */
-       struct ieee802154_addr addr;
+       struct ieee802154_addr_sa addr;
 };
 
 /* get/setsockopt */
index f4f9ee466791a9b9fc0b0d7f74f22e2cf3660ac2..904777c1cd2420486a3df25636f61811ab35c29e 100644 (file)
@@ -65,6 +65,7 @@ struct bt_security {
 #define BT_SECURITY_LOW                1
 #define BT_SECURITY_MEDIUM     2
 #define BT_SECURITY_HIGH       3
+#define BT_SECURITY_FIPS       4
 
 #define BT_DEFER_SETUP 7
 
index 66c1cd87bfe7f9b9d117db340f736884f9d0c4c1..be150cf8cd432298d47860268a1d4566af74481d 100644 (file)
@@ -117,11 +117,18 @@ enum {
        HCI_SERVICE_CACHE,
        HCI_DEBUG_KEYS,
        HCI_DUT_MODE,
+       HCI_FORCE_SC,
+       HCI_FORCE_STATIC_ADDR,
        HCI_UNREGISTER,
        HCI_USER_CHANNEL,
 
        HCI_LE_SCAN,
        HCI_SSP_ENABLED,
+       HCI_SC_ENABLED,
+       HCI_SC_ONLY,
+       HCI_PRIVACY,
+       HCI_RPA_EXPIRED,
+       HCI_RPA_RESOLVING,
        HCI_HS_ENABLED,
        HCI_LE_ENABLED,
        HCI_ADVERTISING,
@@ -133,6 +140,7 @@ enum {
        HCI_FAST_CONNECTABLE,
        HCI_BREDR_ENABLED,
        HCI_6LOWPAN_ENABLED,
+       HCI_LE_SCAN_INTERRUPTED,
 };
 
 /* A mask for the flags that are supposed to remain when a reset happens
@@ -175,6 +183,8 @@ enum {
 #define HCI_CMD_TIMEOUT                msecs_to_jiffies(2000)  /* 2 seconds */
 #define HCI_ACL_TX_TIMEOUT     msecs_to_jiffies(45000) /* 45 seconds */
 #define HCI_AUTO_OFF_TIMEOUT   msecs_to_jiffies(2000)  /* 2 seconds */
+#define HCI_POWER_OFF_TIMEOUT  msecs_to_jiffies(5000)  /* 5 seconds */
+#define HCI_LE_CONN_TIMEOUT    msecs_to_jiffies(20000) /* 20 seconds */
 
 /* HCI data types */
 #define HCI_COMMAND_PKT                0x01
@@ -282,10 +292,14 @@ enum {
 #define LMP_SYNC_TRAIN 0x04
 #define LMP_SYNC_SCAN  0x08
 
+#define LMP_SC         0x01
+#define LMP_PING       0x02
+
 /* Host features */
 #define LMP_HOST_SSP           0x01
 #define LMP_HOST_LE            0x02
 #define LMP_HOST_LE_BREDR      0x04
+#define LMP_HOST_SC            0x08
 
 /* Connection modes */
 #define HCI_CM_ACTIVE  0x0000
@@ -307,6 +321,7 @@ enum {
 #define HCI_LM_TRUSTED 0x0008
 #define HCI_LM_RELIABLE        0x0010
 #define HCI_LM_SECURE  0x0020
+#define HCI_LM_FIPS    0x0040
 
 /* Authentication types */
 #define HCI_AT_NO_BONDING              0x00
@@ -327,17 +342,24 @@ enum {
 #define HCI_LK_LOCAL_UNIT              0x01
 #define HCI_LK_REMOTE_UNIT             0x02
 #define HCI_LK_DEBUG_COMBINATION       0x03
-#define HCI_LK_UNAUTH_COMBINATION      0x04
-#define HCI_LK_AUTH_COMBINATION                0x05
+#define HCI_LK_UNAUTH_COMBINATION_P192 0x04
+#define HCI_LK_AUTH_COMBINATION_P192   0x05
 #define HCI_LK_CHANGED_COMBINATION     0x06
+#define HCI_LK_UNAUTH_COMBINATION_P256 0x07
+#define HCI_LK_AUTH_COMBINATION_P256   0x08
 /* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */
 #define HCI_SMP_STK                    0x80
 #define HCI_SMP_STK_SLAVE              0x81
 #define HCI_SMP_LTK                    0x82
 #define HCI_SMP_LTK_SLAVE              0x83
 
+/* Long Term Key types */
+#define HCI_LTK_UNAUTH                 0x00
+#define HCI_LTK_AUTH                   0x01
+
 /* ---- HCI Error Codes ---- */
 #define HCI_ERROR_AUTH_FAILURE         0x05
+#define HCI_ERROR_MEMORY_EXCEEDED      0x07
 #define HCI_ERROR_CONNECTION_TIMEOUT   0x08
 #define HCI_ERROR_REJ_BAD_ADDR         0x0f
 #define HCI_ERROR_REMOTE_USER_TERM     0x13
@@ -660,6 +682,15 @@ struct hci_rp_set_csb {
 
 #define HCI_OP_START_SYNC_TRAIN                0x0443
 
+#define HCI_OP_REMOTE_OOB_EXT_DATA_REPLY       0x0445
+struct hci_cp_remote_oob_ext_data_reply {
+       bdaddr_t bdaddr;
+       __u8     hash192[16];
+       __u8     randomizer192[16];
+       __u8     hash256[16];
+       __u8     randomizer256[16];
+} __packed;
+
 #define HCI_OP_SNIFF_MODE              0x0803
 struct hci_cp_sniff_mode {
        __le16   handle;
@@ -933,6 +964,26 @@ struct hci_rp_write_sync_train_params {
        __le16  sync_train_int;
 } __packed;
 
+#define HCI_OP_READ_SC_SUPPORT         0x0c79
+struct hci_rp_read_sc_support {
+       __u8    status;
+       __u8    support;
+} __packed;
+
+#define HCI_OP_WRITE_SC_SUPPORT                0x0c7a
+struct hci_cp_write_sc_support {
+       __u8    support;
+} __packed;
+
+#define HCI_OP_READ_LOCAL_OOB_EXT_DATA 0x0c7d
+struct hci_rp_read_local_oob_ext_data {
+       __u8     status;
+       __u8     hash192[16];
+       __u8     randomizer192[16];
+       __u8     hash256[16];
+       __u8     randomizer256[16];
+} __packed;
+
 #define HCI_OP_READ_LOCAL_VERSION      0x1001
 struct hci_rp_read_local_version {
        __u8     status;
@@ -1133,6 +1184,9 @@ struct hci_cp_le_set_scan_enable {
        __u8     filter_dup;
 } __packed;
 
+#define HCI_LE_USE_PEER_ADDR           0x00
+#define HCI_LE_USE_WHITELIST           0x01
+
 #define HCI_OP_LE_CREATE_CONN          0x200d
 struct hci_cp_le_create_conn {
        __le16   scan_interval;
@@ -1157,6 +1211,20 @@ struct hci_rp_le_read_white_list_size {
        __u8    size;
 } __packed;
 
+#define HCI_OP_LE_CLEAR_WHITE_LIST     0x2010
+
+#define HCI_OP_LE_ADD_TO_WHITE_LIST    0x2011
+struct hci_cp_le_add_to_white_list {
+       __u8     bdaddr_type;
+       bdaddr_t bdaddr;
+} __packed;
+
+#define HCI_OP_LE_DEL_FROM_WHITE_LIST  0x2012
+struct hci_cp_le_del_from_white_list {
+       __u8     bdaddr_type;
+       bdaddr_t bdaddr;
+} __packed;
+
 #define HCI_OP_LE_CONN_UPDATE          0x2013
 struct hci_cp_le_conn_update {
        __le16   handle;
@@ -1171,7 +1239,7 @@ struct hci_cp_le_conn_update {
 #define HCI_OP_LE_START_ENC            0x2019
 struct hci_cp_le_start_enc {
        __le16  handle;
-       __u8    rand[8];
+       __le64  rand;
        __le16  ediv;
        __u8    ltk[16];
 } __packed;
@@ -1583,7 +1651,7 @@ struct hci_ev_le_conn_complete {
 #define HCI_EV_LE_LTK_REQ              0x05
 struct hci_ev_le_ltk_req {
        __le16  handle;
-       __u8    random[8];
+       __le64  rand;
        __le16  ediv;
 } __packed;
 
index f2f0cf5865c40a9b92f7a98eb4c53c6834a34d29..dbb788e4f265f4b820a3375c71b65520d2cbcfaf 100644 (file)
@@ -99,9 +99,17 @@ struct smp_ltk {
        u8 type;
        u8 enc_size;
        __le16 ediv;
-       u8 rand[8];
+       __le64 rand;
        u8 val[16];
-} __packed;
+};
+
+struct smp_irk {
+       struct list_head list;
+       bdaddr_t rpa;
+       bdaddr_t bdaddr;
+       u8 addr_type;
+       u8 val[16];
+};
 
 struct link_key {
        struct list_head list;
@@ -114,12 +122,17 @@ struct link_key {
 struct oob_data {
        struct list_head list;
        bdaddr_t bdaddr;
-       u8 hash[16];
-       u8 randomizer[16];
+       u8 hash192[16];
+       u8 randomizer192[16];
+       u8 hash256[16];
+       u8 randomizer256[16];
 };
 
 #define HCI_MAX_SHORT_NAME_LENGTH      10
 
+/* Default LE RPA expiry time, 15 minutes */
+#define HCI_DEFAULT_RPA_TIMEOUT                (15 * 60)
+
 struct amp_assoc {
        __u16   len;
        __u16   offset;
@@ -141,8 +154,9 @@ struct hci_dev {
        __u8            bus;
        __u8            dev_type;
        bdaddr_t        bdaddr;
+       bdaddr_t        random_addr;
        bdaddr_t        static_addr;
-       __u8            own_addr_type;
+       __u8            adv_addr_type;
        __u8            dev_name[HCI_MAX_NAME_LENGTH];
        __u8            short_name[HCI_MAX_SHORT_NAME_LENGTH];
        __u8            eir[HCI_MAX_EIR_LENGTH];
@@ -167,6 +181,7 @@ struct hci_dev {
        __u16           page_scan_interval;
        __u16           page_scan_window;
        __u8            page_scan_type;
+       __u8            le_adv_channel_map;
        __u16           le_scan_interval;
        __u16           le_scan_window;
        __u16           le_conn_min_interval;
@@ -257,19 +272,21 @@ struct hci_dev {
        __u32                   req_status;
        __u32                   req_result;
 
-       struct list_head        mgmt_pending;
+       struct crypto_blkcipher *tfm_aes;
 
        struct discovery_state  discovery;
        struct hci_conn_hash    conn_hash;
-       struct list_head        blacklist;
 
+       struct list_head        mgmt_pending;
+       struct list_head        blacklist;
        struct list_head        uuids;
-
        struct list_head        link_keys;
-
        struct list_head        long_term_keys;
-
+       struct list_head        identity_resolving_keys;
        struct list_head        remote_oob_data;
+       struct list_head        le_white_list;
+       struct list_head        le_conn_params;
+       struct list_head        pend_le_conns;
 
        struct hci_dev_stats    stat;
 
@@ -291,6 +308,11 @@ struct hci_dev {
        __u8                    scan_rsp_data[HCI_MAX_AD_LENGTH];
        __u8                    scan_rsp_data_len;
 
+       __u8                    irk[16];
+       __u32                   rpa_timeout;
+       struct delayed_work     rpa_expired;
+       bdaddr_t                rpa;
+
        int (*open)(struct hci_dev *hdev);
        int (*close)(struct hci_dev *hdev);
        int (*flush)(struct hci_dev *hdev);
@@ -310,6 +332,10 @@ struct hci_conn {
        __u8            dst_type;
        bdaddr_t        src;
        __u8            src_type;
+       bdaddr_t        init_addr;
+       __u8            init_addr_type;
+       bdaddr_t        resp_addr;
+       __u8            resp_addr_type;
        __u16           handle;
        __u16           state;
        __u8            mode;
@@ -332,6 +358,8 @@ struct hci_conn {
        __u8            passkey_entered;
        __u16           disc_timeout;
        __u16           setting;
+       __u16           le_conn_min_interval;
+       __u16           le_conn_max_interval;
        unsigned long   flags;
 
        __u8            remote_cap;
@@ -347,6 +375,7 @@ struct hci_conn {
        struct delayed_work disc_work;
        struct delayed_work auto_accept_work;
        struct delayed_work idle_work;
+       struct delayed_work le_conn_timeout;
 
        struct device   dev;
 
@@ -372,6 +401,22 @@ struct hci_chan {
        __u8            state;
 };
 
+struct hci_conn_params {
+       struct list_head list;
+
+       bdaddr_t addr;
+       u8 addr_type;
+
+       u16 conn_min_interval;
+       u16 conn_max_interval;
+
+       enum {
+               HCI_AUTO_CONN_DISABLED,
+               HCI_AUTO_CONN_ALWAYS,
+               HCI_AUTO_CONN_LINK_LOSS,
+       } auto_connect;
+};
+
 extern struct list_head hci_dev_list;
 extern struct list_head hci_cb_list;
 extern rwlock_t hci_dev_list_lock;
@@ -446,6 +491,8 @@ enum {
        HCI_CONN_LE_SMP_PEND,
        HCI_CONN_MGMT_CONNECTED,
        HCI_CONN_SSP_ENABLED,
+       HCI_CONN_SC_ENABLED,
+       HCI_CONN_AES_CCM,
        HCI_CONN_POWER_SAVE,
        HCI_CONN_REMOTE_OOB,
        HCI_CONN_6LOWPAN,
@@ -458,6 +505,13 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
               test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
 }
 
+static inline bool hci_conn_sc_enabled(struct hci_conn *conn)
+{
+       struct hci_dev *hdev = conn->hdev;
+       return test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
+              test_bit(HCI_CONN_SC_ENABLED, &conn->flags);
+}
+
 static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
@@ -521,6 +575,13 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
        }
 }
 
+static inline unsigned int hci_conn_count(struct hci_dev *hdev)
+{
+       struct hci_conn_hash *c = &hdev->conn_hash;
+
+       return c->acl_num + c->amp_num + c->sco_num + c->le_num;
+}
+
 static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
                                                                __u16 handle)
 {
@@ -594,8 +655,10 @@ void hci_chan_del(struct hci_chan *chan);
 void hci_chan_list_flush(struct hci_conn *conn);
 struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle);
 
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
-                            __u8 dst_type, __u8 sec_level, __u8 auth_type);
+struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
+                               u8 dst_type, u8 sec_level, u8 auth_type);
+struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
+                                u8 sec_level, u8 auth_type);
 struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
                                 __u16 setting);
 int hci_conn_check_link_mode(struct hci_conn *conn);
@@ -606,6 +669,8 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
 
 void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
 
+void hci_le_conn_failed(struct hci_conn *conn, u8 status);
+
 /*
  * hci_conn_get() and hci_conn_put() are used to control the life-time of an
  * "hci_conn" object. They do not guarantee that the hci_conn object is running,
@@ -737,31 +802,64 @@ int hci_inquiry(void __user *arg);
 
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
                                         bdaddr_t *bdaddr, u8 type);
-int hci_blacklist_clear(struct hci_dev *hdev);
 int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 
-int hci_uuids_clear(struct hci_dev *hdev);
+struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev,
+                                         bdaddr_t *bdaddr, u8 type);
+void hci_white_list_clear(struct hci_dev *hdev);
+int hci_white_list_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+
+struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
+                                              bdaddr_t *addr, u8 addr_type);
+int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
+                       u8 auto_connect, u16 conn_min_interval,
+                       u16 conn_max_interval);
+void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
+void hci_conn_params_clear(struct hci_dev *hdev);
 
-int hci_link_keys_clear(struct hci_dev *hdev);
+struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev,
+                                           bdaddr_t *addr, u8 addr_type);
+void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
+void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
+void hci_pend_le_conns_clear(struct hci_dev *hdev);
+
+void hci_update_background_scan(struct hci_dev *hdev);
+
+void hci_uuids_clear(struct hci_dev *hdev);
+
+void hci_link_keys_clear(struct hci_dev *hdev);
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                     bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
-struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
-int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
-               int new_key, u8 authenticated, u8 tk[16], u8 enc_size,
-               __le16 ediv, u8 rand[8]);
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
+                            bool master);
+struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                           u8 addr_type, u8 type, u8 authenticated,
+                           u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand);
 struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                    u8 addr_type);
-int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_smp_ltks_clear(struct hci_dev *hdev);
+                                    u8 addr_type, bool master);
+int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type);
+void hci_smp_ltks_clear(struct hci_dev *hdev);
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
-int hci_remote_oob_data_clear(struct hci_dev *hdev);
+struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa);
+struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                    u8 addr_type);
+struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                           u8 addr_type, u8 val[16], bdaddr_t *rpa);
+void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type);
+void hci_smp_irks_clear(struct hci_dev *hdev);
+
+void hci_remote_oob_data_clear(struct hci_dev *hdev);
 struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
-                                                       bdaddr_t *bdaddr);
-int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
-                                                               u8 *randomizer);
+                                         bdaddr_t *bdaddr);
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                           u8 *hash, u8 *randomizer);
+int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                               u8 *hash192, u8 *randomizer192,
+                               u8 *hash256, u8 *randomizer256);
 int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
@@ -803,9 +901,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_csb_slave_capable(dev)  ((dev)->features[2][0] & LMP_CSB_SLAVE)
 #define lmp_sync_train_capable(dev) ((dev)->features[2][0] & LMP_SYNC_TRAIN)
 #define lmp_sync_scan_capable(dev)  ((dev)->features[2][0] & LMP_SYNC_SCAN)
+#define lmp_sc_capable(dev)         ((dev)->features[2][1] & LMP_SC)
+#define lmp_ping_capable(dev)       ((dev)->features[2][1] & LMP_PING)
 
 /* ----- Host capabilities ----- */
 #define lmp_host_ssp_capable(dev)  ((dev)->features[1][0] & LMP_HOST_SSP)
+#define lmp_host_sc_capable(dev)   ((dev)->features[1][0] & LMP_HOST_SC)
 #define lmp_host_le_capable(dev)   (!!((dev)->features[1][0] & LMP_HOST_LE))
 #define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
 
@@ -1019,6 +1120,26 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type)
        return false;
 }
 
+static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type)
+{
+       if (addr_type != 0x01)
+               return false;
+
+       if ((bdaddr->b[5] & 0xc0) == 0x40)
+              return true;
+
+       return false;
+}
+
+static inline struct smp_irk *hci_get_irk(struct hci_dev *hdev,
+                                         bdaddr_t *bdaddr, u8 addr_type)
+{
+       if (!hci_bdaddr_is_rpa(bdaddr, addr_type))
+               return NULL;
+
+       return hci_find_irk_by_rpa(hdev, bdaddr);
+}
+
 int hci_register_cb(struct hci_cb *hcb);
 int hci_unregister_cb(struct hci_cb *hcb);
 
@@ -1040,6 +1161,9 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
                    const void *param, u8 event);
 void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
 
+void hci_req_add_le_scan_disable(struct hci_request *req);
+void hci_req_add_le_passive_scan(struct hci_request *req);
+
 struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
                               const void *param, u32 timeout);
 struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
@@ -1085,6 +1209,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered);
 void mgmt_discoverable_timeout(struct hci_dev *hdev);
 void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
 void mgmt_connectable(struct hci_dev *hdev, u8 connectable);
+void mgmt_advertising(struct hci_dev *hdev, u8 advertising);
 void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
 void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
                       bool persistent);
@@ -1092,7 +1217,8 @@ void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                           u8 addr_type, u32 flags, u8 *name, u8 name_len,
                           u8 *dev_class);
 void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                             u8 link_type, u8 addr_type, u8 reason);
+                             u8 link_type, u8 addr_type, u8 reason,
+                             bool mgmt_connected);
 void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
                            u8 link_type, u8 addr_type, u8 status);
 void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
@@ -1122,11 +1248,13 @@ void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                      u8 addr_type, u8 status);
 void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
 void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
+void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
 void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
                                    u8 status);
 void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
-void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
-                                            u8 *randomizer, u8 status);
+void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
+                                      u8 *randomizer192, u8 *hash256,
+                                      u8 *randomizer256, u8 status);
 void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                       u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
                       u8 ssp, u8 *eir, u16 eir_len);
@@ -1135,8 +1263,10 @@ void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
 int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
-void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
+void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key);
+void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk);
 void mgmt_reenable_advertising(struct hci_dev *hdev);
+void mgmt_smp_complete(struct hci_conn *conn, bool complete);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
@@ -1168,9 +1298,14 @@ struct hci_sec_filter {
 
 void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
                                        u16 latency, u16 to_multiplier);
-void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
+void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
                                                        __u8 ltk[16]);
 
+int hci_update_random_address(struct hci_request *req, bool require_privacy,
+                             u8 *own_addr_type);
+void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                              u8 *bdaddr_type);
+
 #define SCO_AIRMODE_MASK       0x0003
 #define SCO_AIRMODE_CVSD       0x0000
 #define SCO_AIRMODE_TRANSP     0x0003
index dbc4a89984ca67287715a8279b2d9793e7d2eebe..4abdcb220e3ac7a0558a9a0115b873a5312f3f07 100644 (file)
@@ -91,6 +91,7 @@ struct l2cap_conninfo {
 #define L2CAP_LM_TRUSTED       0x0008
 #define L2CAP_LM_RELIABLE      0x0010
 #define L2CAP_LM_SECURE                0x0020
+#define L2CAP_LM_FIPS          0x0040
 
 /* L2CAP command codes */
 #define L2CAP_COMMAND_REJ      0x01
@@ -623,6 +624,9 @@ struct l2cap_conn {
        __u32                   rx_len;
        __u8                    tx_ident;
 
+       struct sk_buff_head     pending_rx;
+       struct work_struct      pending_rx_work;
+
        __u8                    disc_reason;
 
        struct delayed_work     security_timer;
@@ -647,7 +651,7 @@ struct l2cap_user {
 #define L2CAP_CHAN_RAW                 1
 #define L2CAP_CHAN_CONN_LESS           2
 #define L2CAP_CHAN_CONN_ORIENTED       3
-#define L2CAP_CHAN_CONN_FIX_A2MP       4
+#define L2CAP_CHAN_FIXED               4
 
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
@@ -853,7 +857,6 @@ static inline long l2cap_chan_no_get_sndtimeo(struct l2cap_chan *chan)
 }
 
 extern bool disable_ertm;
-extern bool enable_lecoc;
 
 int l2cap_init_sockets(void);
 void l2cap_cleanup_sockets(void);
@@ -878,6 +881,7 @@ int l2cap_ertm_init(struct l2cap_chan *chan);
 void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
+void l2cap_conn_update_id_addr(struct hci_conn *hcon);
 void l2cap_send_conn_req(struct l2cap_chan *chan);
 void l2cap_move_start(struct l2cap_chan *chan);
 void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
index 518c5c84e39a67ef4c9789eacd8d88117bf6ccbd..0326648fd799c1120aad54e3906803841932f27a 100644 (file)
@@ -94,6 +94,9 @@ struct mgmt_rp_read_index_list {
 #define MGMT_SETTING_HS                        0x00000100
 #define MGMT_SETTING_LE                        0x00000200
 #define MGMT_SETTING_ADVERTISING       0x00000400
+#define MGMT_SETTING_SECURE_CONN       0x00000800
+#define MGMT_SETTING_DEBUG_KEYS                0x00001000
+#define MGMT_SETTING_PRIVACY           0x00002000
 
 #define MGMT_OP_READ_INFO              0x0004
 #define MGMT_READ_INFO_SIZE            0
@@ -180,11 +183,11 @@ struct mgmt_cp_load_link_keys {
 
 struct mgmt_ltk_info {
        struct mgmt_addr_info addr;
-       __u8    authenticated;
+       __u8    type;
        __u8    master;
        __u8    enc_size;
        __le16  ediv;
-       __u8    rand[8];
+       __le64  rand;
        __u8    val[16];
 } __packed;
 
@@ -294,6 +297,12 @@ struct mgmt_rp_read_local_oob_data {
        __u8    hash[16];
        __u8    randomizer[16];
 } __packed;
+struct mgmt_rp_read_local_oob_ext_data {
+       __u8    hash192[16];
+       __u8    randomizer192[16];
+       __u8    hash256[16];
+       __u8    randomizer256[16];
+} __packed;
 
 #define MGMT_OP_ADD_REMOTE_OOB_DATA    0x0021
 struct mgmt_cp_add_remote_oob_data {
@@ -302,6 +311,14 @@ struct mgmt_cp_add_remote_oob_data {
        __u8    randomizer[16];
 } __packed;
 #define MGMT_ADD_REMOTE_OOB_DATA_SIZE  (MGMT_ADDR_INFO_SIZE + 32)
+struct mgmt_cp_add_remote_oob_ext_data {
+       struct mgmt_addr_info addr;
+       __u8    hash192[16];
+       __u8    randomizer192[16];
+       __u8    hash256[16];
+       __u8    randomizer256[16];
+} __packed;
+#define MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE (MGMT_ADDR_INFO_SIZE + 64)
 
 #define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022
 struct mgmt_cp_remove_remote_oob_data {
@@ -369,6 +386,29 @@ struct mgmt_cp_set_scan_params {
 } __packed;
 #define MGMT_SET_SCAN_PARAMS_SIZE      4
 
+#define MGMT_OP_SET_SECURE_CONN                0x002D
+
+#define MGMT_OP_SET_DEBUG_KEYS         0x002E
+
+#define MGMT_OP_SET_PRIVACY            0x002F
+struct mgmt_cp_set_privacy {
+       __u8 privacy;
+       __u8 irk[16];
+} __packed;
+#define MGMT_SET_PRIVACY_SIZE          17
+
+struct mgmt_irk_info {
+       struct mgmt_addr_info addr;
+       __u8 val[16];
+} __packed;
+
+#define MGMT_OP_LOAD_IRKS              0x0030
+struct mgmt_cp_load_irks {
+       __le16 irk_count;
+       struct mgmt_irk_info irks[0];
+} __packed;
+#define MGMT_LOAD_IRKS_SIZE            2
+
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
        __le16  opcode;
@@ -504,3 +544,10 @@ struct mgmt_ev_passkey_notify {
        __le32  passkey;
        __u8    entered;
 } __packed;
+
+#define MGMT_EV_NEW_IRK                        0x0018
+struct mgmt_ev_new_irk {
+       __u8     store_hint;
+       bdaddr_t rpa;
+       struct mgmt_irk_info irk;
+} __packed;
index 486213a1aed8d07ad63aaba57957e7a651657696..2611cc389d7d65d03cf298061bf3e4ed32c304cd 100644 (file)
@@ -238,9 +238,11 @@ int  rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
                                                                u8 channel);
 int  rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
 int  rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
+void rfcomm_dlc_send_noerror(struct rfcomm_dlc *d, struct sk_buff *skb);
 int  rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
 int  rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
 void rfcomm_dlc_accept(struct rfcomm_dlc *d);
+struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel);
 
 #define rfcomm_dlc_lock(d)     spin_lock(&d->lock)
 #define rfcomm_dlc_unlock(d)   spin_unlock(&d->lock)
@@ -295,6 +297,7 @@ struct rfcomm_conninfo {
 #define RFCOMM_LM_TRUSTED      0x0008
 #define RFCOMM_LM_RELIABLE     0x0010
 #define RFCOMM_LM_SECURE       0x0020
+#define RFCOMM_LM_FIPS         0x0040
 
 #define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk)
 
@@ -323,11 +326,16 @@ int  rfcomm_connect_ind(struct rfcomm_session *s, u8 channel,
 #define RFCOMMGETDEVINFO       _IOR('R', 211, int)
 #define RFCOMMSTEALDLC         _IOW('R', 220, int)
 
+/* rfcomm_dev.flags bit definitions */
 #define RFCOMM_REUSE_DLC      0
 #define RFCOMM_RELEASE_ONHUP  1
 #define RFCOMM_HANGUP_NOW     2
 #define RFCOMM_TTY_ATTACHED   3
-#define RFCOMM_TTY_RELEASED   4
+#define RFCOMM_DEFUNCT_BIT4   4          /* don't reuse this bit - userspace visible */
+
+/* rfcomm_dev.status bit definitions */
+#define RFCOMM_DEV_RELEASED   0
+#define RFCOMM_TTY_OWNED      1
 
 struct rfcomm_dev_req {
        s16      dev_id;
index 9f90554e88c48a1342c0d1116e1c47ba0b875d81..8c9ba44fb7cf37a3505226094dd022e1859086a5 100644 (file)
@@ -2206,7 +2206,12 @@ struct cfg80211_qos_map {
  * @set_cqm_txe_config: Configure connection quality monitor TX error
  *     thresholds.
  * @sched_scan_start: Tell the driver to start a scheduled scan.
- * @sched_scan_stop: Tell the driver to stop an ongoing scheduled scan.
+ * @sched_scan_stop: Tell the driver to stop an ongoing scheduled scan. This
+ *     call must stop the scheduled scan and be ready for starting a new one
+ *     before it returns, i.e. @sched_scan_start may be called immediately
+ *     after that again and should not fail in that case. The driver should
+ *     not call cfg80211_sched_scan_stopped() for a requested stop (when this
+ *     method returns 0.)
  *
  * @mgmt_frame_register: Notify driver that a management frame type was
  *     registered. Note that this callback may not sleep, and cannot run
@@ -2465,7 +2470,8 @@ struct cfg80211_ops {
 
        int     (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev,
                             u8 *peer, u8 action_code,  u8 dialog_token,
-                            u16 status_code, const u8 *buf, size_t len);
+                            u16 status_code, u32 peer_capability,
+                            const u8 *buf, size_t len);
        int     (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
                             u8 *peer, enum nl80211_tdls_operation oper);
 
@@ -2610,9 +2616,12 @@ struct ieee80211_iface_limit {
  *     only in special cases.
  * @radar_detect_widths: bitmap of channel widths supported for radar detection
  *
- * These examples can be expressed as follows:
+ * With this structure the driver can describe which interface
+ * combinations it supports concurrently.
  *
- * Allow #STA <= 1, #AP <= 1, matching BI, channels = 1, 2 total:
+ * Examples:
+ *
+ * 1. Allow #STA <= 1, #AP <= 1, matching BI, channels = 1, 2 total:
  *
  *  struct ieee80211_iface_limit limits1[] = {
  *     { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), },
@@ -2626,7 +2635,7 @@ struct ieee80211_iface_limit {
  *  };
  *
  *
- * Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total:
+ * 2. Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total:
  *
  *  struct ieee80211_iface_limit limits2[] = {
  *     { .max = 8, .types = BIT(NL80211_IFTYPE_AP) |
@@ -2640,7 +2649,8 @@ struct ieee80211_iface_limit {
  *  };
  *
  *
- * Allow #STA <= 1, #{P2P-client,P2P-GO} <= 3 on two channels, 4 total.
+ * 3. Allow #STA <= 1, #{P2P-client,P2P-GO} <= 3 on two channels, 4 total.
+ *
  * This allows for an infrastructure connection and three P2P connections.
  *
  *  struct ieee80211_iface_limit limits3[] = {
@@ -2790,7 +2800,7 @@ struct wiphy_vendor_command {
  * @perm_addr: permanent MAC address of this device
  * @addr_mask: If the device supports multiple MAC addresses by masking,
  *     set this to a mask with variable bits set to 1, e.g. if the last
- *     four bits are variable then set it to 00:...:00:0f. The actual
+ *     four bits are variable then set it to 00-00-00-00-00-0f. The actual
  *     variable bits shall be determined by the interfaces added, with
  *     interfaces not matching the mask being rejected to be brought up.
  * @n_addresses: number of addresses in @addresses.
index 77eb53fabfb00d6e446d89066937621b22c68e44..e01a826f2a9c8cef455f217eab07a3ec2669280e 100644 (file)
@@ -54,10 +54,9 @@ struct dst_entry {
 #define DST_NOHASH             0x0008
 #define DST_NOCACHE            0x0010
 #define DST_NOCOUNT            0x0020
-#define DST_NOPEER             0x0040
-#define DST_FAKE_RTABLE                0x0080
-#define DST_XFRM_TUNNEL                0x0100
-#define DST_XFRM_QUEUE         0x0200
+#define DST_FAKE_RTABLE                0x0040
+#define DST_XFRM_TUNNEL                0x0080
+#define DST_XFRM_QUEUE         0x0100
 
        unsigned short          pending_confirm;
 
index bee3741e5a6f2ddeba6ffce29b82ab8d1f24ca8f..64fd24836650b7ea14a5c6ba8278066bbb21bf0d 100644 (file)
@@ -219,6 +219,7 @@ struct flow_cache_object *flow_cache_lookup(struct net *net,
                                            u8 dir, flow_resolve_t resolver,
                                            void *ctx);
 int flow_cache_init(struct net *net);
+void flow_cache_fini(struct net *net);
 
 void flow_cache_flush(struct net *net);
 void flow_cache_flush_deferred(struct net *net);
index ee59f8b188ddfb081c948b27f54ac73839a9d2ef..c7ae0ac528dc1e5e1d3c2d5456c2d0e5221b6933 100644 (file)
            (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \
        } while (0)
 
-#define IEEE802154_FC_SECEN            (1 << 3)
-#define IEEE802154_FC_FRPEND           (1 << 4)
-#define IEEE802154_FC_ACK_REQ          (1 << 5)
-#define IEEE802154_FC_INTRA_PAN                (1 << 6)
+#define IEEE802154_FC_SECEN_SHIFT      3
+#define IEEE802154_FC_SECEN            (1 << IEEE802154_FC_SECEN_SHIFT)
+#define IEEE802154_FC_FRPEND_SHIFT     4
+#define IEEE802154_FC_FRPEND           (1 << IEEE802154_FC_FRPEND_SHIFT)
+#define IEEE802154_FC_ACK_REQ_SHIFT    5
+#define IEEE802154_FC_ACK_REQ          (1 << IEEE802154_FC_ACK_REQ_SHIFT)
+#define IEEE802154_FC_INTRA_PAN_SHIFT  6
+#define IEEE802154_FC_INTRA_PAN                (1 << IEEE802154_FC_INTRA_PAN_SHIFT)
 
 #define IEEE802154_FC_SAMODE_SHIFT     14
 #define IEEE802154_FC_SAMODE_MASK      (3 << IEEE802154_FC_SAMODE_SHIFT)
 #define IEEE802154_FC_DAMODE_SHIFT     10
 #define IEEE802154_FC_DAMODE_MASK      (3 << IEEE802154_FC_DAMODE_SHIFT)
 
+#define IEEE802154_FC_VERSION_SHIFT    12
+#define IEEE802154_FC_VERSION_MASK     (3 << IEEE802154_FC_VERSION_SHIFT)
+#define IEEE802154_FC_VERSION(x)       ((x & IEEE802154_FC_VERSION_MASK) >> IEEE802154_FC_VERSION_SHIFT)
+
 #define IEEE802154_FC_SAMODE(x)                \
        (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT)
 
 #define IEEE802154_FC_DAMODE(x)                \
        (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
 
+#define IEEE802154_SCF_SECLEVEL_MASK           7
+#define IEEE802154_SCF_SECLEVEL_SHIFT          0
+#define IEEE802154_SCF_SECLEVEL(x)             (x & IEEE802154_SCF_SECLEVEL_MASK)
+#define IEEE802154_SCF_KEY_ID_MODE_SHIFT       3
+#define IEEE802154_SCF_KEY_ID_MODE_MASK                (3 << IEEE802154_SCF_KEY_ID_MODE_SHIFT)
+#define IEEE802154_SCF_KEY_ID_MODE(x)          \
+       ((x & IEEE802154_SCF_KEY_ID_MODE_MASK) >> IEEE802154_SCF_KEY_ID_MODE_SHIFT)
+
+#define IEEE802154_SCF_KEY_IMPLICIT            0
+#define IEEE802154_SCF_KEY_INDEX               1
+#define IEEE802154_SCF_KEY_SHORT_INDEX         2
+#define IEEE802154_SCF_KEY_HW_INDEX            3
 
 /* MAC footer size */
 #define IEEE802154_MFR_SIZE    2 /* 2 octets */
index 97b2e34d87f7d1d19e0dd258b6694c1d9edaab01..e1717cbf609b67d6761dc68ed9d8a40a202bbfb3 100644 (file)
 #define IEEE802154_NETDEVICE_H
 
 #include <net/af_ieee802154.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
 
-struct ieee802154_frag_info {
-       __be16 d_tag;
-       u16 d_size;
-       u8 d_offset;
+struct ieee802154_sechdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u8 level:3,
+          key_id_mode:2,
+          reserved:3;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       u8 reserved:3,
+          key_id_mode:2,
+          level:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+       u8 key_id;
+       __le32 frame_counter;
+       union {
+               __le32 short_src;
+               __le64 extended_src;
+       };
+};
+
+struct ieee802154_addr {
+       u8 mode;
+       __le16 pan_id;
+       union {
+               __le16 short_addr;
+               __le64 extended_addr;
+       };
+};
+
+struct ieee802154_hdr_fc {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u16 type:3,
+           security_enabled:1,
+           frame_pending:1,
+           ack_request:1,
+           intra_pan:1,
+           reserved:3,
+           dest_addr_mode:2,
+           version:2,
+           source_addr_mode:2;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       u16 reserved:1,
+           intra_pan:1,
+           ack_request:1,
+           frame_pending:1,
+           security_enabled:1,
+           type:3,
+           source_addr_mode:2,
+           version:2,
+           dest_addr_mode:2,
+           reserved2:2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 };
 
+struct ieee802154_hdr {
+       struct ieee802154_hdr_fc fc;
+       u8 seq;
+       struct ieee802154_addr source;
+       struct ieee802154_addr dest;
+       struct ieee802154_sechdr sec;
+};
+
+/* pushes hdr onto the skb. fields of hdr->fc that can be calculated from
+ * the contents of hdr will be, and the actual value of those bits in
+ * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame
+ * version, if SECEN is set.
+ */
+int ieee802154_hdr_push(struct sk_buff *skb, const struct ieee802154_hdr *hdr);
+
+/* pulls the entire 802.15.4 header off of the skb, including the security
+ * header, and performs pan id decompression
+ */
+int ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr);
+
+/* parses the frame control, sequence number of address fields in a given skb
+ * and stores them into hdr, performing pan id decompression and length checks
+ * to be suitable for use in header_ops.parse
+ */
+int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
+                             struct ieee802154_hdr *hdr);
+
+static inline int ieee802154_hdr_length(struct sk_buff *skb)
+{
+       struct ieee802154_hdr hdr;
+       int len = ieee802154_hdr_pull(skb, &hdr);
+
+       if (len > 0)
+               skb_push(skb, len);
+
+       return len;
+}
+
+static inline bool ieee802154_addr_equal(const struct ieee802154_addr *a1,
+                                        const struct ieee802154_addr *a2)
+{
+       if (a1->pan_id != a2->pan_id || a1->mode != a2->mode)
+               return false;
+
+       if ((a1->mode == IEEE802154_ADDR_LONG &&
+            a1->extended_addr != a2->extended_addr) ||
+           (a1->mode == IEEE802154_ADDR_SHORT &&
+            a1->short_addr != a2->short_addr))
+               return false;
+
+       return true;
+}
+
+static inline __le64 ieee802154_devaddr_from_raw(const void *raw)
+{
+       u64 temp;
+
+       memcpy(&temp, raw, IEEE802154_ADDR_LEN);
+       return (__force __le64)swab64(temp);
+}
+
+static inline void ieee802154_devaddr_to_raw(void *raw, __le64 addr)
+{
+       u64 temp = swab64((__force u64)addr);
+
+       memcpy(raw, &temp, IEEE802154_ADDR_LEN);
+}
+
+static inline void ieee802154_addr_from_sa(struct ieee802154_addr *a,
+                                          const struct ieee802154_addr_sa *sa)
+{
+       a->mode = sa->addr_type;
+       a->pan_id = cpu_to_le16(sa->pan_id);
+
+       switch (a->mode) {
+       case IEEE802154_ADDR_SHORT:
+               a->short_addr = cpu_to_le16(sa->short_addr);
+               break;
+       case IEEE802154_ADDR_LONG:
+               a->extended_addr = ieee802154_devaddr_from_raw(sa->hwaddr);
+               break;
+       }
+}
+
+static inline void ieee802154_addr_to_sa(struct ieee802154_addr_sa *sa,
+                                        const struct ieee802154_addr *a)
+{
+       sa->addr_type = a->mode;
+       sa->pan_id = le16_to_cpu(a->pan_id);
+
+       switch (a->mode) {
+       case IEEE802154_ADDR_SHORT:
+               sa->short_addr = le16_to_cpu(a->short_addr);
+               break;
+       case IEEE802154_ADDR_LONG:
+               ieee802154_devaddr_to_raw(sa->hwaddr, a->extended_addr);
+               break;
+       }
+}
+
 /*
  * A control block of skb passed between the ARPHRD_IEEE802154 device
  * and other stack parts.
  */
 struct ieee802154_mac_cb {
        u8 lqi;
-       struct ieee802154_addr sa;
-       struct ieee802154_addr da;
        u8 flags;
        u8 seq;
-       struct ieee802154_frag_info frag_info;
+       struct ieee802154_addr source;
+       struct ieee802154_addr dest;
 };
 
 static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
@@ -57,23 +208,17 @@ static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
 
 #define MAC_CB_FLAG_ACKREQ             (1 << 3)
 #define MAC_CB_FLAG_SECEN              (1 << 4)
-#define MAC_CB_FLAG_INTRAPAN           (1 << 5)
 
-static inline int mac_cb_is_ackreq(struct sk_buff *skb)
+static inline bool mac_cb_is_ackreq(struct sk_buff *skb)
 {
        return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ;
 }
 
-static inline int mac_cb_is_secen(struct sk_buff *skb)
+static inline bool mac_cb_is_secen(struct sk_buff *skb)
 {
        return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN;
 }
 
-static inline int mac_cb_is_intrapan(struct sk_buff *skb)
-{
-       return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN;
-}
-
 static inline int mac_cb_type(struct sk_buff *skb)
 {
        return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK;
@@ -99,7 +244,7 @@ struct ieee802154_mlme_ops {
                        u8 channel, u8 page, u8 cap);
        int (*assoc_resp)(struct net_device *dev,
                        struct ieee802154_addr *addr,
-                       u16 short_addr, u8 status);
+                       __le16 short_addr, u8 status);
        int (*disassoc_req)(struct net_device *dev,
                        struct ieee802154_addr *addr,
                        u8 reason);
@@ -118,8 +263,8 @@ struct ieee802154_mlme_ops {
         * FIXME: these should become the part of PIB/MIB interface.
         * However we still don't have IB interface of any kind
         */
-       u16 (*get_pan_id)(const struct net_device *dev);
-       u16 (*get_short_addr)(const struct net_device *dev);
+       __le16 (*get_pan_id)(const struct net_device *dev);
+       __le16 (*get_short_addr)(const struct net_device *dev);
        u8 (*get_dsn)(const struct net_device *dev);
 };
 
index b885d75cede4d3ea4f71809fb8b93c9d8de7d7c0..25064c28e059e2e42d46dcaf3209a2ff517a7a82 100644 (file)
@@ -187,6 +187,7 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
 #define NET_INC_STATS(net, field)      SNMP_INC_STATS((net)->mib.net_statistics, field)
 #define NET_INC_STATS_BH(net, field)   SNMP_INC_STATS_BH((net)->mib.net_statistics, field)
 #define NET_INC_STATS_USER(net, field)         SNMP_INC_STATS_USER((net)->mib.net_statistics, field)
+#define NET_ADD_STATS(net, field, adnd)        SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd)
 #define NET_ADD_STATS_BH(net, field, adnd) SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd)
 #define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd)
 
index 48ed75c21260b8dd17e681021311bb8dae4f2617..e77c10405d515da16071461fe9f7385d8ac08556 100644 (file)
@@ -129,6 +129,7 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
 int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
                      struct ip_tunnel_parm *p);
 void ip_tunnel_setup(struct net_device *dev, int net_id);
+void ip_tunnel_dst_reset_all(struct ip_tunnel *t);
 
 /* Extract dsfield from inner protocol */
 static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
index 4f0f29dce0aae64c98ffd9cf2cf6e26859e9c4d3..86faa413b37d043979cd5983164a65060f4f2965 100644 (file)
  *
  * Secondly, when the hardware handles fragmentation, the frame handed to
  * the driver from mac80211 is the MSDU, not the MPDU.
- *
- * Finally, for received frames, the driver is able to indicate that it has
- * filled a radiotap header and put that in front of the frame; if it does
- * not do so then mac80211 may add this under certain circumstances.
  */
 
 /**
@@ -1507,8 +1503,6 @@ struct ieee80211_tx_control {
  * @IEEE80211_HW_CONNECTION_MONITOR:
  *     The hardware performs its own connection monitoring, including
  *     periodic keep-alives to the AP and probing the AP on beacon loss.
- *     When this flag is set, signaling beacon-loss will cause an immediate
- *     change to disassociated state.
  *
  * @IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC:
  *     This device needs to get data from beacon before association (i.e.
@@ -1644,10 +1638,6 @@ enum ieee80211_hw_flags {
  *     the hw can report back.
  * @max_rate_tries: maximum number of tries for each stage
  *
- * @napi_weight: weight used for NAPI polling.  You must specify an
- *     appropriate value here if a napi_poll operation is provided
- *     by your driver.
- *
  * @max_rx_aggregation_subframes: maximum buffer size (number of
  *     sub-frames) to be used for A-MPDU block ack receiver
  *     aggregation.
@@ -1701,7 +1691,6 @@ struct ieee80211_hw {
        int vif_data_size;
        int sta_data_size;
        int chanctx_data_size;
-       int napi_weight;
        u16 queues;
        u16 max_listen_interval;
        s8 max_signal;
@@ -2471,6 +2460,7 @@ enum ieee80211_roc_type {
  *     This process will continue until sched_scan_stop is called.
  *
  * @sched_scan_stop: Tell the hardware to stop an ongoing scheduled scan.
+ *     In this case, ieee80211_sched_scan_stopped() must not be called.
  *
  * @sw_scan_start: Notifier function that is called just before a software scan
  *     is started. Can be NULL, if the driver doesn't need this notification.
@@ -2624,8 +2614,6 @@ enum ieee80211_roc_type {
  *     callback. They must then call ieee80211_chswitch_done() to indicate
  *     completion of the channel switch.
  *
- * @napi_poll: Poll Rx queue for incoming data frames.
- *
  * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device.
  *     Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may
  *     reject TX/RX mask combinations they cannot support by returning -EINVAL
@@ -2820,7 +2808,7 @@ struct ieee80211_ops {
                                struct ieee80211_vif *vif,
                                struct cfg80211_sched_scan_request *req,
                                struct ieee80211_sched_scan_ies *ies);
-       void (*sched_scan_stop)(struct ieee80211_hw *hw,
+       int (*sched_scan_stop)(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif);
        void (*sw_scan_start)(struct ieee80211_hw *hw);
        void (*sw_scan_complete)(struct ieee80211_hw *hw);
@@ -2884,7 +2872,6 @@ struct ieee80211_ops {
        void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop);
        void (*channel_switch)(struct ieee80211_hw *hw,
                               struct ieee80211_channel_switch *ch_switch);
-       int (*napi_poll)(struct ieee80211_hw *hw, int budget);
        int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
        int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
 
@@ -3166,21 +3153,21 @@ void ieee80211_free_hw(struct ieee80211_hw *hw);
  */
 void ieee80211_restart_hw(struct ieee80211_hw *hw);
 
-/** ieee80211_napi_schedule - schedule NAPI poll
- *
- * Use this function to schedule NAPI polling on a device.
- *
- * @hw: the hardware to start polling
- */
-void ieee80211_napi_schedule(struct ieee80211_hw *hw);
-
-/** ieee80211_napi_complete - complete NAPI polling
- *
- * Use this function to finish NAPI polling on a device.
+/**
+ * ieee80211_napi_add - initialize mac80211 NAPI context
+ * @hw: the hardware to initialize the NAPI context on
+ * @napi: the NAPI context to initialize
+ * @napi_dev: dummy NAPI netdevice, here to not waste the space if the
+ *     driver doesn't use NAPI
+ * @poll: poll function
+ * @weight: default weight
  *
- * @hw: the hardware to stop polling
+ * See also netif_napi_add().
  */
-void ieee80211_napi_complete(struct ieee80211_hw *hw);
+void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi,
+                       struct net_device *napi_dev,
+                       int (*poll)(struct napi_struct *, int),
+                       int weight);
 
 /**
  * ieee80211_rx - receive frame
index 8ca3d04e7558266bac7226533415ef540e5b0032..a591053cae6305c399eabb745c6f1764c41bc8be 100644 (file)
@@ -20,6 +20,7 @@
 #define NET_MAC802154_H
 
 #include <net/af_ieee802154.h>
+#include <linux/skbuff.h>
 
 /* General MAC frame format:
  *  2 bytes: Frame Control
@@ -50,7 +51,7 @@ struct ieee802154_hw_addr_filt {
                                 * devices across independent networks.
                                 */
        __le16  short_addr;
-       u8      ieee_addr[IEEE802154_ADDR_LEN];
+       __le64  ieee_addr;
        u8      pan_coord;
 };
 
@@ -153,8 +154,7 @@ struct ieee802154_ops {
        int             (*set_hw_addr_filt)(struct ieee802154_dev *dev,
                                          struct ieee802154_hw_addr_filt *filt,
                                            unsigned long changed);
-       int             (*ieee_addr)(struct ieee802154_dev *dev,
-                                    u8 addr[IEEE802154_ADDR_LEN]);
+       int             (*ieee_addr)(struct ieee802154_dev *dev, __le64 addr);
        int             (*set_txpower)(struct ieee802154_dev *dev, int db);
        int             (*set_lbt)(struct ieee802154_dev *dev, bool on);
        int             (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode);
index b2ac6246b7e0abe156b26a06bf9a4463331baa6e..37252f71a38037d0e969699dc7376e6dcae1c5ec 100644 (file)
@@ -73,10 +73,17 @@ struct nf_conn_help {
 
 struct nf_conn {
        /* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
-           plus 1 for any connection(s) we are `master' for */
+        * plus 1 for any connection(s) we are `master' for
+        *
+        * Hint, SKB address this struct and refcnt via skb->nfct and
+        * helpers nf_conntrack_get() and nf_conntrack_put().
+        * Helper nf_ct_put() equals nf_conntrack_put() by dec refcnt,
+        * beware nf_ct_get() is different and don't inc refcnt.
+        */
        struct nf_conntrack ct_general;
 
-       spinlock_t lock;
+       spinlock_t      lock;
+       u16             cpu;
 
        /* XXX should I move this to the tail ? - Y.K */
        /* These are my tuples; original and reply */
index 15308b8eb5b5218330c3043c46a02537d00779a2..cc0c1882760270f21bd1cc7080cece06afd518d8 100644 (file)
@@ -77,6 +77,13 @@ print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
             const struct nf_conntrack_l3proto *l3proto,
             const struct nf_conntrack_l4proto *proto);
 
-extern spinlock_t nf_conntrack_lock ;
+#ifdef CONFIG_LOCKDEP
+# define CONNTRACK_LOCKS 8
+#else
+# define CONNTRACK_LOCKS 1024
+#endif
+extern spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS];
+
+extern spinlock_t nf_conntrack_expect_lock;
 
 #endif /* _NF_CONNTRACK_CORE_H */
index c985695283b3a34d5d78aa99b062ab4dfb839c18..dec6336bf850f77928f54f4cd04d37b3ebe3e16a 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <uapi/linux/netfilter/xt_connlabel.h>
 
+#define NF_CT_LABELS_MAX_SIZE ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE)
+
 struct nf_conn_labels {
        u8 words;
        unsigned long bits[];
@@ -29,7 +31,7 @@ static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct)
        u8 words;
 
        words = ACCESS_ONCE(net->ct.label_words);
-       if (words == 0 || WARN_ON_ONCE(words > 8))
+       if (words == 0)
                return NULL;
 
        cl_ext = nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS,
index e7e14ffe0f6a0e0f545af45864aa248980250da2..e6bc14d8fa9a9a4b324fac9df5a47e64277f2aa8 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/list.h>
 #include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/nf_tables.h>
 #include <net/netlink.h>
@@ -288,7 +289,8 @@ struct nft_expr_ops {
        int                             (*init)(const struct nft_ctx *ctx,
                                                const struct nft_expr *expr,
                                                const struct nlattr * const tb[]);
-       void                            (*destroy)(const struct nft_expr *expr);
+       void                            (*destroy)(const struct nft_ctx *ctx,
+                                                  const struct nft_expr *expr);
        int                             (*dump)(struct sk_buff *skb,
                                                const struct nft_expr *expr);
        int                             (*validate)(const struct nft_ctx *ctx,
@@ -325,13 +327,15 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
  *     @handle: rule handle
  *     @genmask: generation mask
  *     @dlen: length of expression data
+ *     @ulen: length of user data (used for comments)
  *     @data: expression data
  */
 struct nft_rule {
        struct list_head                list;
-       u64                             handle:46,
+       u64                             handle:42,
                                        genmask:2,
-                                       dlen:16;
+                                       dlen:12,
+                                       ulen:8;
        unsigned char                   data[]
                __attribute__((aligned(__alignof__(struct nft_expr))));
 };
@@ -340,19 +344,13 @@ struct nft_rule {
  *     struct nft_rule_trans - nf_tables rule update in transaction
  *
  *     @list: used internally
+ *     @ctx: rule context
  *     @rule: rule that needs to be updated
- *     @chain: chain that this rule belongs to
- *     @table: table for which this chain applies
- *     @nlh: netlink header of the message that contain this update
- *     @family: family expressesed as AF_*
  */
 struct nft_rule_trans {
        struct list_head                list;
+       struct nft_ctx                  ctx;
        struct nft_rule                 *rule;
-       const struct nft_chain          *chain;
-       const struct nft_table          *table;
-       const struct nlmsghdr           *nlh;
-       u8                              family;
 };
 
 static inline struct nft_expr *nft_expr_first(const struct nft_rule *rule)
@@ -370,6 +368,11 @@ static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule)
        return (struct nft_expr *)&rule->data[rule->dlen];
 }
 
+static inline void *nft_userdata(const struct nft_rule *rule)
+{
+       return (void *)&rule->data[rule->dlen];
+}
+
 /*
  * The last pointer isn't really necessary, but the compiler isn't able to
  * determine that the result of nft_expr_last() is always the same since it
@@ -521,6 +524,9 @@ void nft_unregister_chain_type(const struct nf_chain_type *);
 int nft_register_expr(struct nft_expr_type *);
 void nft_unregister_expr(struct nft_expr_type *);
 
+#define nft_dereference(p)                                     \
+       nfnl_dereference(p, NFNL_SUBSYS_NFTABLES)
+
 #define MODULE_ALIAS_NFT_FAMILY(family)        \
        MODULE_ALIAS("nft-afinfo-" __stringify(family))
 
index fbcc7fa536dc4ab49440d4566e63fedf8b860d2a..773cce308bc61ce312c4a5ecab0464ba84e1ce41 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/list_nulls.h>
 #include <linux/atomic.h>
 #include <linux/netfilter/nf_conntrack_tcp.h>
+#include <linux/seqlock.h>
 
 struct ctl_table_header;
 struct nf_conntrack_ecache;
@@ -62,6 +63,13 @@ struct nf_ip_net {
 #endif
 };
 
+struct ct_pcpu {
+       spinlock_t              lock;
+       struct hlist_nulls_head unconfirmed;
+       struct hlist_nulls_head dying;
+       struct hlist_nulls_head tmpl;
+};
+
 struct netns_ct {
        atomic_t                count;
        unsigned int            expect_count;
@@ -83,12 +91,11 @@ struct netns_ct {
        int                     sysctl_checksum;
 
        unsigned int            htable_size;
+       seqcount_t              generation;
        struct kmem_cache       *nf_conntrack_cachep;
        struct hlist_nulls_head *hash;
        struct hlist_head       *expect_hash;
-       struct hlist_nulls_head unconfirmed;
-       struct hlist_nulls_head dying;
-       struct hlist_nulls_head tmpl;
+       struct ct_pcpu __percpu *pcpu_lists;
        struct ip_conntrack_stat __percpu *stat;
        struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
        struct nf_exp_event_notifier __rcu *nf_expect_event_cb;
index 51f0dce7b6437cec03a75116b923c704bf8e9b9d..3492434baf88e9dffb3da763de75db36480d9eb9 100644 (file)
@@ -64,7 +64,6 @@ struct netns_xfrm {
 
        /* flow cache part */
        struct flow_cache       flow_cache_global;
-       struct kmem_cache       *flow_cachep;
        atomic_t                flow_cache_genid;
        struct list_head        flow_cache_gc_list;
        spinlock_t              flow_cache_gc_lock;
index 99d2ba1c7e03f76d7a92e95691fb002535de52eb..b23548e0409848530b1c7f94fb805601c46e583c 100644 (file)
@@ -52,7 +52,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
  * Note: This is in section 7.3.2 of the IEEE 802.15.4 document.
  */
 int ieee802154_nl_assoc_confirm(struct net_device *dev,
-               u16 short_addr, u8 status);
+               __le16 short_addr, u8 status);
 
 /**
  * ieee802154_nl_disassoc_indic - Notify userland of disassociation.
@@ -111,8 +111,8 @@ int ieee802154_nl_scan_confirm(struct net_device *dev,
  * Note: This API cannot indicate a beacon frame for a coordinator
  *       operating in long addressing mode.
  */
-int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid,
-               u16 coord_addr);
+int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
+               __le16 coord_addr);
 
 /**
  * ieee802154_nl_start_confirm - Notify userland of completion of start.
index 5c3f7c3624aa00214572c47cd3b6dbb3777d93ee..625e65b12366dd9503cd504cb699b2b8fb883a79 100644 (file)
@@ -1488,6 +1488,11 @@ static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
  */
 #define sock_owned_by_user(sk) ((sk)->sk_lock.owned)
 
+static inline void sock_release_ownership(struct sock *sk)
+{
+       sk->sk_lock.owned = 0;
+}
+
 /*
  * Macro so as to not evaluate some arguments when
  * lockdep is not enabled.
@@ -2186,7 +2191,6 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
 {
 #define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL)                      | \
                           (1UL << SOCK_RCVTSTAMP)                      | \
-                          (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)       | \
                           (1UL << SOCK_TIMESTAMPING_SOFTWARE)          | \
                           (1UL << SOCK_TIMESTAMPING_RAW_HARDWARE)      | \
                           (1UL << SOCK_TIMESTAMPING_SYS_HARDWARE))
@@ -2252,8 +2256,12 @@ void sock_net_set(struct sock *sk, struct net *net)
  */
 static inline void sk_change_net(struct sock *sk, struct net *net)
 {
-       put_net(sock_net(sk));
-       sock_net_set(sk, hold_net(net));
+       struct net *current_net = sock_net(sk);
+
+       if (!net_eq(current_net, net)) {
+               put_net(current_net);
+               sock_net_set(sk, hold_net(net));
+       }
 }
 
 static inline struct sock *skb_steal_sock(struct sk_buff *skb)
index 93eab0b9da6044b263724d580c9f8d0f99771a86..bb253b9b2f06924eeef980cb84ea1421a2b7b540 100644 (file)
@@ -1304,7 +1304,8 @@ struct tcp_fastopen_request {
        /* Fast Open cookie. Size 0 means a cookie request */
        struct tcp_fastopen_cookie      cookie;
        struct msghdr                   *data;  /* data in MSG_FASTOPEN */
-       u16                             copied; /* queued in tcp_connect() */
+       size_t                          size;
+       int                             copied; /* queued in tcp_connect() */
 };
 void tcp_free_fastopen_req(struct tcp_sock *tp);
 
index 7c13ef6d6564dbb41cd4a673708763f35dfc2e85..32682ae47b3fe6d88e7750120089efc791b38894 100644 (file)
@@ -1702,6 +1702,11 @@ static inline int xfrm_acquire_is_on(struct net *net)
 }
 #endif
 
+static inline int aead_len(struct xfrm_algo_aead *alg)
+{
+       return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
+}
+
 static inline int xfrm_alg_len(const struct xfrm_algo *alg)
 {
        return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
@@ -1740,6 +1745,12 @@ static inline int xfrm_replay_clone(struct xfrm_state *x,
        return 0;
 }
 
+static inline struct xfrm_algo_aead *xfrm_algo_aead_clone(struct xfrm_algo_aead *orig)
+{
+       return kmemdup(orig, aead_len(orig), GFP_KERNEL);
+}
+
+
 static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig)
 {
        return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL);
index 68d92e36facda52f6e4b249e108bd43c8847e92e..6e89ef6c11c1a42c853a8f87021bbf1244a14ffc 100644 (file)
@@ -449,14 +449,22 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
 /* dapm audio pin control and status */
 int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
                            const char *pin);
+int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                    const char *pin);
 int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
                             const char *pin);
+int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                     const char *pin);
 int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                const char *pin);
 int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
                                const char *pin);
 int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
 int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
                                  const char *pin);
+int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                          const char *pin);
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
                                const char *pin);
 void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
index ae5a17111968c7ca8bc8667a65d16393532ffbde..4483fadfa68d8fdc744743d6bc5bcd52de301608 100644 (file)
@@ -12,6 +12,7 @@ struct iscsit_transport {
        int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
        int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
        void (*iscsit_free_np)(struct iscsi_np *);
+       void (*iscsit_wait_conn)(struct iscsi_conn *);
        void (*iscsit_free_conn)(struct iscsi_conn *);
        int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
        int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);
index ddc179b7a1052aa6c3fb9df408e3b5ad9e50d792..1fef3e6e943632e6b2e1619c6536bc328a81eb8f 100644 (file)
@@ -83,7 +83,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
                ),
 
        TP_fast_assign(
-               __entry->client_id = clnt->cl_clid;
+               __entry->client_id = clnt ? clnt->cl_clid : -1;
                __entry->task_id = task->tk_pid;
                __entry->action = action;
                __entry->runstate = task->tk_runstate;
@@ -91,7 +91,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
                __entry->flags = task->tk_flags;
                ),
 
-       TP_printk("task:%u@%u flags=%4.4x state=%4.4lx status=%d action=%pf",
+       TP_printk("task:%u@%d flags=%4.4x state=%4.4lx status=%d action=%pf",
                __entry->task_id, __entry->client_id,
                __entry->flags,
                __entry->runstate,
index c7bbbe794e65cdd0a41c7235bcee6e9718970876..464ea82e10dbf1f1a519b75c52f9e129a5a715e0 100644 (file)
@@ -287,11 +287,11 @@ TRACE_EVENT(writeback_queue_io,
                __field(int,            reason)
        ),
        TP_fast_assign(
-               unsigned long older_than_this = work->older_than_this;
+               unsigned long *older_than_this = work->older_than_this;
                strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
-               __entry->older  = older_than_this;
+               __entry->older  = older_than_this ?  *older_than_this : 0;
                __entry->age    = older_than_this ?
-                                 (jiffies - older_than_this) * 1000 / HZ : -1;
+                                 (jiffies - *older_than_this) * 1000 / HZ : -1;
                __entry->moved  = moved;
                __entry->reason = work->reason;
        ),
index a20a9b4d38713f5a92982457f0e8f330b0bfd58c..dde8041f40d2e8a29a25a6205dd38577f2b46bce 100644 (file)
@@ -692,9 +692,13 @@ __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \
 __SYSCALL(__NR_kcmp, sys_kcmp)
 #define __NR_finit_module 273
 __SYSCALL(__NR_finit_module, sys_finit_module)
+#define __NR_sched_setattr 274
+__SYSCALL(__NR_sched_setattr, sys_sched_setattr)
+#define __NR_sched_getattr 275
+__SYSCALL(__NR_sched_getattr, sys_sched_getattr)
 
 #undef __NR_syscalls
-#define __NR_syscalls 274
+#define __NR_syscalls 276
 
 /*
  * All syscalls below here should go away really,
index df944ed206a8e4bd23d9f9a3ec9e08c9e0ad6e3b..7e2e1863db16e02fa15e1edc109adefda8236ba7 100644 (file)
@@ -96,6 +96,7 @@ struct can_ctrlmode {
 #define CAN_CTRLMODE_3_SAMPLES         0x04    /* Triple sampling mode */
 #define CAN_CTRLMODE_ONE_SHOT          0x08    /* One-Shot mode */
 #define CAN_CTRLMODE_BERR_REPORTING    0x10    /* Bus-error reporting */
+#define CAN_CTRLMODE_FD                        0x20    /* CAN FD mode */
 
 /*
  * CAN device statistics
@@ -122,6 +123,8 @@ enum {
        IFLA_CAN_RESTART_MS,
        IFLA_CAN_RESTART,
        IFLA_CAN_BERR_COUNTER,
+       IFLA_CAN_DATA_BITTIMING,
+       IFLA_CAN_DATA_BITTIMING_CONST,
        __IFLA_CAN_MAX
 };
 
index 750ba67e0dc3d7b60ca851efca1d2bff34991e08..0f8210b8e0bc47ac0b7faab45a12ca6dcfbdf72d 100644 (file)
@@ -90,6 +90,7 @@
 #define ETH_P_TDLS     0x890D          /* TDLS */
 #define ETH_P_FIP      0x8914          /* FCoE Initialization Protocol */
 #define ETH_P_80221    0x8917          /* IEEE 802.21 Media Independent Handover Protocol */
+#define ETH_P_LOOPBACK 0x9000          /* Ethernet loopback packet, per IEEE 802.3 */
 #define ETH_P_QINQ1    0x9100          /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
 #define ETH_P_QINQ2    0x9200          /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
 #define ETH_P_QINQ3    0x9300          /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
index 25d3b2f79c022e92cfd8f851e0f9ae8a2f7b731a..78c2f2e799208a467b75c8035b4d3362365362bb 100644 (file)
@@ -82,6 +82,8 @@ enum {
        IPSET_ATTR_PROTO,       /* 7 */
        IPSET_ATTR_CADT_FLAGS,  /* 8 */
        IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,     /* 9 */
+       IPSET_ATTR_MARK,        /* 10 */
+       IPSET_ATTR_MARKMASK,    /* 11 */
        /* Reserve empty slots */
        IPSET_ATTR_CADT_MAX = 16,
        /* Create-only specific attributes */
@@ -144,6 +146,7 @@ enum ipset_errno {
        IPSET_ERR_IPADDR_IPV6,
        IPSET_ERR_COUNTER,
        IPSET_ERR_COMMENT,
+       IPSET_ERR_INVALID_MARKMASK,
 
        /* Type specific error codes */
        IPSET_ERR_TYPE_SPECIFIC = 4352,
@@ -182,9 +185,18 @@ enum ipset_cadt_flags {
        IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS),
        IPSET_FLAG_BIT_WITH_COMMENT = 4,
        IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT),
+       IPSET_FLAG_BIT_WITH_FORCEADD = 5,
+       IPSET_FLAG_WITH_FORCEADD = (1 << IPSET_FLAG_BIT_WITH_FORCEADD),
        IPSET_FLAG_CADT_MAX     = 15,
 };
 
+/* The flag bits which correspond to the non-extension create flags */
+enum ipset_create_flags {
+       IPSET_CREATE_FLAG_BIT_FORCEADD = 0,
+       IPSET_CREATE_FLAG_FORCEADD = (1 << IPSET_CREATE_FLAG_BIT_FORCEADD),
+       IPSET_CREATE_FLAG_BIT_MAX = 7,
+};
+
 /* Commands with settype-specific attributes */
 enum ipset_adt {
        IPSET_ADD,
index 83c985a6170bd52938764732f45a70d09ae2a28e..c88ccbfda5f1b111a5fa43e1d1803bcccf95b521 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef _LINUX_NF_TABLES_H
 #define _LINUX_NF_TABLES_H
 
-#define NFT_CHAIN_MAXNAMELEN 32
+#define NFT_CHAIN_MAXNAMELEN   32
+#define NFT_USERDATA_MAXLEN    256
 
 enum nft_registers {
        NFT_REG_VERDICT,
@@ -156,6 +157,7 @@ enum nft_chain_attributes {
  * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
  * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes)
  * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
+ * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
  */
 enum nft_rule_attributes {
        NFTA_RULE_UNSPEC,
@@ -165,6 +167,7 @@ enum nft_rule_attributes {
        NFTA_RULE_EXPRESSIONS,
        NFTA_RULE_COMPAT,
        NFTA_RULE_POSITION,
+       NFTA_RULE_USERDATA,
        __NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX          (__NFTA_RULE_MAX - 1)
@@ -601,6 +604,7 @@ enum nft_ct_keys {
        NFT_CT_PROTOCOL,
        NFT_CT_PROTO_SRC,
        NFT_CT_PROTO_DST,
+       NFT_CT_LABELS,
 };
 
 /**
index a12e6cae5132569815271c352508c48001c1b51e..ff72cab3cd3a1355b03a1e5e54aff51d65802086 100644 (file)
  *     passed, all channels allowed for the current regulatory domain
  *     are used.  Extra IEs can also be passed from the userspace by
  *     using the %NL80211_ATTR_IE attribute.
- * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan.  Returns -ENOENT
- *     if scheduled scan is not running.
+ * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if
+ *     scheduled scan is not running. The caller may assume that as soon
+ *     as the call returns, it is safe to start a new scheduled scan again.
  * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
  *     results available.
  * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
@@ -1575,6 +1576,9 @@ enum nl80211_commands {
  *     advertise values that cannot always be met. In such cases, an attempt
  *     to add a new station entry with @NL80211_CMD_NEW_STATION may fail.
  *
+ * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
+ *     As specified in the &enum nl80211_tdls_peer_capability.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1908,6 +1912,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_MAX_AP_ASSOC_STA,
 
+       NL80211_ATTR_TDLS_PEER_CAPABILITY,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2437,10 +2443,7 @@ enum nl80211_reg_type {
  *     in KHz. This is not a center a frequency but an actual regulatory
  *     band edge.
  * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
- *     frequency range, in KHz. If not present or 0, maximum available
- *     bandwidth should be calculated base on contiguous rules and wider
- *     channels will be allowed to cross multiple contiguous/overlapping
- *     frequency ranges.
+ *     frequency range, in KHz.
  * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
  *     for a given frequency range. The value is in mBi (100 * dBi).
  *     If you don't have one then don't send this.
@@ -2511,6 +2514,9 @@ enum nl80211_sched_scan_match_attr {
  * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed,
  *     this includes probe requests or modes of operation that require
  *     beaconing.
+ * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
+ *     base on contiguous rules and wider channels will be allowed to cross
+ *     multiple contiguous/overlapping frequency ranges.
  */
 enum nl80211_reg_rule_flags {
        NL80211_RRF_NO_OFDM             = 1<<0,
@@ -2522,6 +2528,7 @@ enum nl80211_reg_rule_flags {
        NL80211_RRF_PTMP_ONLY           = 1<<6,
        NL80211_RRF_NO_IR               = 1<<7,
        __NL80211_RRF_NO_IBSS           = 1<<8,
+       NL80211_RRF_AUTO_BW             = 1<<11,
 };
 
 #define NL80211_RRF_PASSIVE_SCAN       NL80211_RRF_NO_IR
@@ -3843,11 +3850,6 @@ enum nl80211_ap_sme_features {
  * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
  *     to work properly to suppport receiving regulatory hints from
  *     cellular base stations.
- * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active
- *     P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel
- *     in the interface combinations, even when it's only used for scan
- *     and remain-on-channel. This could be due to, for example, the
- *     remain-on-channel implementation requiring a channel context.
  * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of
  *     equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
  *     mode
@@ -3889,7 +3891,7 @@ enum nl80211_feature_flags {
        NL80211_FEATURE_HT_IBSS                         = 1 << 1,
        NL80211_FEATURE_INACTIVITY_TIMER                = 1 << 2,
        NL80211_FEATURE_CELL_BASE_REG_HINTS             = 1 << 3,
-       NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL        = 1 << 4,
+       /* bit 4 is reserved - don't use */
        NL80211_FEATURE_SAE                             = 1 << 5,
        NL80211_FEATURE_LOW_PRIORITY_SCAN               = 1 << 6,
        NL80211_FEATURE_SCAN_FLUSH                      = 1 << 7,
@@ -4079,4 +4081,20 @@ struct nl80211_vendor_cmd_info {
        __u32 subcmd;
 };
 
+/**
+ * enum nl80211_tdls_peer_capability - TDLS peer flags.
+ *
+ * Used by tdls_mgmt() to determine which conditional elements need
+ * to be added to TDLS Setup frames.
+ *
+ * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable.
+ * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable.
+ * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable.
+ */
+enum nl80211_tdls_peer_capability {
+       NL80211_TDLS_PEER_HT = 1<<0,
+       NL80211_TDLS_PEER_VHT = 1<<1,
+       NL80211_TDLS_PEER_WMM = 1<<2,
+};
+
 #endif /* __LINUX_NL80211_H */
index eb03090cdced5aac82787cf3154c2430b7410924..9c7fd4c9249f2c72395fcaf2ac953f782a3e2b59 100644 (file)
@@ -561,7 +561,6 @@ asmlinkage void __init start_kernel(void)
        init_timers();
        hrtimers_init();
        softirq_init();
-       acpi_early_init();
        timekeeping_init();
        time_init();
        sched_clock_postinit();
@@ -613,6 +612,7 @@ asmlinkage void __init start_kernel(void)
        calibrate_delay();
        pidmap_init();
        anon_vma_init();
+       acpi_early_init();
 #ifdef CONFIG_X86
        if (efi_enabled(EFI_RUNTIME_SERVICES))
                efi_enter_virtual_mode();
index 383d638340b8417c8e31f53b935f8e8d833b2707..5bb8bfe671496e55b6c62df1d28922454a2a2dcf 100644 (file)
@@ -22,6 +22,16 @@ static void *get_mq(ctl_table *table)
        return which;
 }
 
+static int proc_mq_dointvec(ctl_table *table, int write,
+                           void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct ctl_table mq_table;
+       memcpy(&mq_table, table, sizeof(mq_table));
+       mq_table.data = get_mq(table);
+
+       return proc_dointvec(&mq_table, write, buffer, lenp, ppos);
+}
+
 static int proc_mq_dointvec_minmax(ctl_table *table, int write,
        void __user *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -33,12 +43,10 @@ static int proc_mq_dointvec_minmax(ctl_table *table, int write,
                                        lenp, ppos);
 }
 #else
+#define proc_mq_dointvec NULL
 #define proc_mq_dointvec_minmax NULL
 #endif
 
-static int msg_queues_limit_min = MIN_QUEUESMAX;
-static int msg_queues_limit_max = HARD_QUEUESMAX;
-
 static int msg_max_limit_min = MIN_MSGMAX;
 static int msg_max_limit_max = HARD_MSGMAX;
 
@@ -51,9 +59,7 @@ static ctl_table mq_sysctls[] = {
                .data           = &init_ipc_ns.mq_queues_max,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_mq_dointvec_minmax,
-               .extra1         = &msg_queues_limit_min,
-               .extra2         = &msg_queues_limit_max,
+               .proc_handler   = proc_mq_dointvec,
        },
        {
                .procname       = "msg_max",
index ccf1f9fd263acdfae7dc56a87bceddd3170f69d9..c3b31179122c326342597d40cd58db11d51da940 100644 (file)
@@ -433,9 +433,9 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
                error = -EACCES;
                goto out_unlock;
        }
-       if (ipc_ns->mq_queues_count >= HARD_QUEUESMAX ||
-           (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max &&
-            !capable(CAP_SYS_RESOURCE))) {
+
+       if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max &&
+           !capable(CAP_SYS_RESOURCE)) {
                error = -ENOSPC;
                goto out_unlock;
        }
index 34c5a2310fbf9545eeff2e3fa803c8a361031bb3..3392d3e0254ac5d93199c0b00e271cbb0b2bfc9c 100644 (file)
@@ -182,7 +182,7 @@ struct audit_buffer {
 
 struct audit_reply {
        __u32 portid;
-       pid_t pid;
+       struct net *net;        
        struct sk_buff *skb;
 };
 
@@ -500,7 +500,7 @@ int audit_send_list(void *_dest)
 {
        struct audit_netlink_list *dest = _dest;
        struct sk_buff *skb;
-       struct net *net = get_net_ns_by_pid(dest->pid);
+       struct net *net = dest->net;
        struct audit_net *aunet = net_generic(net, audit_net_id);
 
        /* wait for parent to finish and send an ACK */
@@ -510,6 +510,7 @@ int audit_send_list(void *_dest)
        while ((skb = __skb_dequeue(&dest->q)) != NULL)
                netlink_unicast(aunet->nlsk, skb, dest->portid, 0);
 
+       put_net(net);
        kfree(dest);
 
        return 0;
@@ -543,7 +544,7 @@ out_kfree_skb:
 static int audit_send_reply_thread(void *arg)
 {
        struct audit_reply *reply = (struct audit_reply *)arg;
-       struct net *net = get_net_ns_by_pid(reply->pid);
+       struct net *net = reply->net;
        struct audit_net *aunet = net_generic(net, audit_net_id);
 
        mutex_lock(&audit_cmd_mutex);
@@ -552,12 +553,13 @@ static int audit_send_reply_thread(void *arg)
        /* Ignore failure. It'll only happen if the sender goes away,
           because our timeout is set to infinite. */
        netlink_unicast(aunet->nlsk , reply->skb, reply->portid, 0);
+       put_net(net);
        kfree(reply);
        return 0;
 }
 /**
  * audit_send_reply - send an audit reply message via netlink
- * @portid: netlink port to which to send reply
+ * @request_skb: skb of request we are replying to (used to target the reply)
  * @seq: sequence number
  * @type: audit message type
  * @done: done (last) flag
@@ -568,9 +570,11 @@ static int audit_send_reply_thread(void *arg)
  * Allocates an skb, builds the netlink message, and sends it to the port id.
  * No failure notifications.
  */
-static void audit_send_reply(__u32 portid, int seq, int type, int done,
+static void audit_send_reply(struct sk_buff *request_skb, int seq, int type, int done,
                             int multi, const void *payload, int size)
 {
+       u32 portid = NETLINK_CB(request_skb).portid;
+       struct net *net = sock_net(NETLINK_CB(request_skb).sk);
        struct sk_buff *skb;
        struct task_struct *tsk;
        struct audit_reply *reply = kmalloc(sizeof(struct audit_reply),
@@ -583,8 +587,8 @@ static void audit_send_reply(__u32 portid, int seq, int type, int done,
        if (!skb)
                goto out;
 
+       reply->net = get_net(net);
        reply->portid = portid;
-       reply->pid = task_pid_vnr(current);
        reply->skb = skb;
 
        tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply");
@@ -673,8 +677,7 @@ static int audit_get_feature(struct sk_buff *skb)
 
        seq = nlmsg_hdr(skb)->nlmsg_seq;
 
-       audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
-                        &af, sizeof(af));
+       audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &af, sizeof(af));
 
        return 0;
 }
@@ -794,8 +797,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                s.backlog               = skb_queue_len(&audit_skb_queue);
                s.version               = AUDIT_VERSION_LATEST;
                s.backlog_wait_time     = audit_backlog_wait_time;
-               audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
-                                &s, sizeof(s));
+               audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &s, sizeof(s));
                break;
        }
        case AUDIT_SET: {
@@ -905,7 +907,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                           seq, data, nlmsg_len(nlh));
                break;
        case AUDIT_LIST_RULES:
-               err = audit_list_rules_send(NETLINK_CB(skb).portid, seq);
+               err = audit_list_rules_send(skb, seq);
                break;
        case AUDIT_TRIM:
                audit_trim_trees();
@@ -970,8 +972,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        memcpy(sig_data->ctx, ctx, len);
                        security_release_secctx(ctx, len);
                }
-               audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_SIGNAL_INFO,
-                               0, 0, sig_data, sizeof(*sig_data) + len);
+               audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
+                                sig_data, sizeof(*sig_data) + len);
                kfree(sig_data);
                break;
        case AUDIT_TTY_GET: {
@@ -983,8 +985,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                s.log_passwd = tsk->signal->audit_tty_log_passwd;
                spin_unlock(&tsk->sighand->siglock);
 
-               audit_send_reply(NETLINK_CB(skb).portid, seq,
-                                AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
+               audit_send_reply(skb, seq, AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
                break;
        }
        case AUDIT_TTY_SET: {
index 57cc64d67718903eebeab175030348df648b4f17..8df132214606f2b06e08e916196779b1aee64ad6 100644 (file)
@@ -247,7 +247,7 @@ extern void             audit_panic(const char *message);
 
 struct audit_netlink_list {
        __u32 portid;
-       pid_t pid;
+       struct net *net;
        struct sk_buff_head q;
 };
 
index 67ccf0e7cca92412f457175d5ff3e784b254966a..135944a7b28ab901a400d06fd583d831ac8167b9 100644 (file)
@@ -916,7 +916,7 @@ static int audit_tree_handle_event(struct fsnotify_group *group,
                                   struct fsnotify_mark *inode_mark,
                                   struct fsnotify_mark *vfsmount_mark,
                                   u32 mask, void *data, int data_type,
-                                  const unsigned char *file_name)
+                                  const unsigned char *file_name, u32 cookie)
 {
        return 0;
 }
index 2596fac5dcb4552a0d574decada597424df0587b..70b4554d2fbe093e4f83a045ed84705c7a9cffe0 100644 (file)
@@ -471,7 +471,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
                                    struct fsnotify_mark *inode_mark,
                                    struct fsnotify_mark *vfsmount_mark,
                                    u32 mask, void *data, int data_type,
-                                   const unsigned char *dname)
+                                   const unsigned char *dname, u32 cookie)
 {
        struct inode *inode;
        struct audit_parent *parent;
index 14a78cca384edb9cf8f36dc3f7fb5340c267c623..92062fd6cc8cec4deff933c04848782bfdcded11 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/security.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
 #include "audit.h"
 
 /*
@@ -1065,11 +1067,13 @@ int audit_rule_change(int type, __u32 portid, int seq, void *data,
 
 /**
  * audit_list_rules_send - list the audit rules
- * @portid: target portid for netlink audit messages
+ * @request_skb: skb of request we are replying to (used to target the reply)
  * @seq: netlink audit message sequence (serial) number
  */
-int audit_list_rules_send(__u32 portid, int seq)
+int audit_list_rules_send(struct sk_buff *request_skb, int seq)
 {
+       u32 portid = NETLINK_CB(request_skb).portid;
+       struct net *net = sock_net(NETLINK_CB(request_skb).sk);
        struct task_struct *tsk;
        struct audit_netlink_list *dest;
        int err = 0;
@@ -1083,8 +1087,8 @@ int audit_list_rules_send(__u32 portid, int seq)
        dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
        if (!dest)
                return -ENOMEM;
+       dest->net = get_net(net);
        dest->portid = portid;
-       dest->pid = task_pid_vnr(current);
        skb_queue_head_init(&dest->q);
 
        mutex_lock(&audit_filter_mutex);
index e2f46ba37f7243c4278de77a8c8536ddc4c0aad5..105f273b6f86a74984d2b62b7d3ba19f95369a78 100644 (file)
@@ -886,7 +886,9 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
                 * per-subsystem and moved to css->id so that lookups are
                 * successful until the target css is released.
                 */
+               mutex_lock(&cgroup_mutex);
                idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
+               mutex_unlock(&cgroup_mutex);
                cgrp->id = -1;
 
                call_rcu(&cgrp->rcu_head, cgroup_free_rcu);
@@ -1566,10 +1568,10 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                mutex_lock(&cgroup_mutex);
                mutex_lock(&cgroup_root_mutex);
 
-               root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp,
-                                          0, 1, GFP_KERNEL);
-               if (root_cgrp->id < 0)
+               ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL);
+               if (ret < 0)
                        goto unlock_drop;
+               root_cgrp->id = ret;
 
                /* Check for name clashes with existing mounts */
                ret = -EBUSY;
@@ -2763,10 +2765,7 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add)
         */
        update_before = cgroup_serial_nr_next;
 
-       mutex_unlock(&cgroup_mutex);
-
        /* add/rm files for all cgroups created before */
-       rcu_read_lock();
        css_for_each_descendant_pre(css, cgroup_css(root, ss)) {
                struct cgroup *cgrp = css->cgroup;
 
@@ -2775,23 +2774,19 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add)
 
                inode = cgrp->dentry->d_inode;
                dget(cgrp->dentry);
-               rcu_read_unlock();
-
                dput(prev);
                prev = cgrp->dentry;
 
+               mutex_unlock(&cgroup_mutex);
                mutex_lock(&inode->i_mutex);
                mutex_lock(&cgroup_mutex);
                if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp))
                        ret = cgroup_addrm_files(cgrp, cfts, is_add);
-               mutex_unlock(&cgroup_mutex);
                mutex_unlock(&inode->i_mutex);
-
-               rcu_read_lock();
                if (ret)
                        break;
        }
-       rcu_read_unlock();
+       mutex_unlock(&cgroup_mutex);
        dput(prev);
        deactivate_super(sb);
        return ret;
@@ -2910,9 +2905,14 @@ static void cgroup_enable_task_cg_lists(void)
                 * We should check if the process is exiting, otherwise
                 * it will race with cgroup_exit() in that the list
                 * entry won't be deleted though the process has exited.
+                * Do it while holding siglock so that we don't end up
+                * racing against cgroup_exit().
                 */
+               spin_lock_irq(&p->sighand->siglock);
                if (!(p->flags & PF_EXITING) && list_empty(&p->cg_list))
                        list_add(&p->cg_list, &task_css_set(p)->tasks);
+               spin_unlock_irq(&p->sighand->siglock);
+
                task_unlock(p);
        } while_each_thread(g, p);
        read_unlock(&tasklist_lock);
@@ -4158,7 +4158,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
        struct cgroup *cgrp;
        struct cgroup_name *name;
        struct cgroupfs_root *root = parent->root;
-       int ssid, err = 0;
+       int ssid, err;
        struct cgroup_subsys *ss;
        struct super_block *sb = root->sb;
 
@@ -4168,18 +4168,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                return -ENOMEM;
 
        name = cgroup_alloc_name(dentry);
-       if (!name)
+       if (!name) {
+               err = -ENOMEM;
                goto err_free_cgrp;
+       }
        rcu_assign_pointer(cgrp->name, name);
 
-       /*
-        * Temporarily set the pointer to NULL, so idr_find() won't return
-        * a half-baked cgroup.
-        */
-       cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
-       if (cgrp->id < 0)
-               goto err_free_name;
-
        /*
         * Only live parents can have children.  Note that the liveliness
         * check isn't strictly necessary because cgroup_mkdir() and
@@ -4189,7 +4183,17 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
         */
        if (!cgroup_lock_live_group(parent)) {
                err = -ENODEV;
-               goto err_free_id;
+               goto err_free_name;
+       }
+
+       /*
+        * Temporarily set the pointer to NULL, so idr_find() won't return
+        * a half-baked cgroup.
+        */
+       cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
+       if (cgrp->id < 0) {
+               err = -ENOMEM;
+               goto err_unlock;
        }
 
        /* Grab a reference on the superblock so the hierarchy doesn't
@@ -4221,7 +4225,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
         */
        err = cgroup_create_file(dentry, S_IFDIR | mode, sb);
        if (err < 0)
-               goto err_unlock;
+               goto err_free_id;
        lockdep_assert_held(&dentry->d_inode->i_mutex);
 
        cgrp->serial_nr = cgroup_serial_nr_next++;
@@ -4257,12 +4261,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
 
        return 0;
 
-err_unlock:
-       mutex_unlock(&cgroup_mutex);
-       /* Release the reference count that we took on the superblock */
-       deactivate_super(sb);
 err_free_id:
        idr_remove(&root->cgroup_idr, cgrp->id);
+       /* Release the reference count that we took on the superblock */
+       deactivate_super(sb);
+err_unlock:
+       mutex_unlock(&cgroup_mutex);
 err_free_name:
        kfree(rcu_dereference_raw(cgrp->name));
 err_free_cgrp:
index 4410ac6a55f1d9ae410976e3a8e7315acf88a61b..e6b1b66afe526acfa2a9ecbfc5bad9da76e8d9b4 100644 (file)
@@ -974,12 +974,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
  *    Temporarilly set tasks mems_allowed to target nodes of migration,
  *    so that the migration code can allocate pages on these nodes.
  *
- *    Call holding cpuset_mutex, so current's cpuset won't change
- *    during this call, as manage_mutex holds off any cpuset_attach()
- *    calls.  Therefore we don't need to take task_lock around the
- *    call to guarantee_online_mems(), as we know no one is changing
- *    our task's cpuset.
- *
  *    While the mm_struct we are migrating is typically from some
  *    other task, the task_struct mems_allowed that we are hacking
  *    is for our current task, which must allocate new pages for that
@@ -996,8 +990,10 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
 
        do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
 
+       rcu_read_lock();
        mems_cs = effective_nodemask_cpuset(task_cs(tsk));
        guarantee_online_mems(mems_cs, &tsk->mems_allowed);
+       rcu_read_unlock();
 }
 
 /*
@@ -2486,9 +2482,9 @@ int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
 
        task_lock(current);
        cs = nearest_hardwall_ancestor(task_cs(current));
+       allowed = node_isset(node, cs->mems_allowed);
        task_unlock(current);
 
-       allowed = node_isset(node, cs->mems_allowed);
        mutex_unlock(&callback_mutex);
        return allowed;
 }
index 56003c6edfd38c03e8dd523f1efb01d99bcf2e84..fa0b2d4ad83c5f7a08dfecf27d16d33d928a80f2 100644 (file)
@@ -7856,14 +7856,14 @@ static void perf_pmu_rotate_stop(struct pmu *pmu)
 static void __perf_event_exit_context(void *__info)
 {
        struct perf_event_context *ctx = __info;
-       struct perf_event *event, *tmp;
+       struct perf_event *event;
 
        perf_pmu_rotate_stop(ctx->pmu);
 
-       list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry)
-               __perf_remove_from_context(event);
-       list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry)
+       rcu_read_lock();
+       list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
                __perf_remove_from_context(event);
+       rcu_read_unlock();
 }
 
 static void perf_event_exit_cpu_context(int cpu)
@@ -7887,11 +7887,11 @@ static void perf_event_exit_cpu(int cpu)
 {
        struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
 
+       perf_event_exit_cpu_context(cpu);
+
        mutex_lock(&swhash->hlist_mutex);
        swevent_hlist_release(swhash);
        mutex_unlock(&swhash->hlist_mutex);
-
-       perf_event_exit_cpu_context(cpu);
 }
 #else
 static inline void perf_event_exit_cpu(int cpu) { }
index cf68bb36fe5885dd2ba7b9c9ccef3c5165a320d3..f14033700c25cbc6872ccc2e60d33ee25a3493e9 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/topology.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
index 481a13c43b1708d3501a7f686760573c4eab6a34..d3bf660cb57fb8a26e55c3605dffc78ce82035f4 100644 (file)
@@ -802,8 +802,7 @@ static irqreturn_t irq_thread_fn(struct irq_desc *desc,
 
 static void wake_threads_waitq(struct irq_desc *desc)
 {
-       if (atomic_dec_and_test(&desc->threads_active) &&
-           waitqueue_active(&desc->wait_for_threads))
+       if (atomic_dec_and_test(&desc->threads_active))
                wake_up(&desc->wait_for_threads);
 }
 
index eacb8bd8cab4e1205230ecfdde12483be9846cf7..aba9c545a0e3940481f3b5ce54221906edb760e2 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kbd_kern.h>
 #include <linux/vt.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include "power.h"
 
 #define SUSPEND_CONSOLE        (MAX_NR_CONSOLES-1)
index 6631e1ef55ab0970f095b42ec350982abd8d9678..ebdd9c1a86b4dfd7840df57c64f13f72a1401156 100644 (file)
@@ -549,14 +549,14 @@ static int create_hash_tables(void)
                struct page *page;
 
                page = alloc_pages_exact_node(node,
-                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                0);
                if (!page)
                        goto out_cleanup;
                per_cpu(cpu_profile_hits, cpu)[1]
                                = (struct profile_hit *)page_address(page);
                page = alloc_pages_exact_node(node,
-                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                0);
                if (!page)
                        goto out_cleanup;
index b46131ef6aab0ac48149482a03f8354330adf188..6edbef296ece25a6ee68facac279445414692368 100644 (file)
@@ -1952,7 +1952,7 @@ static int dl_overflow(struct task_struct *p, int policy,
 {
 
        struct dl_bw *dl_b = dl_bw_of(task_cpu(p));
-       u64 period = attr->sched_period;
+       u64 period = attr->sched_period ?: attr->sched_deadline;
        u64 runtime = attr->sched_runtime;
        u64 new_bw = dl_policy(policy) ? to_ratio(period, runtime) : 0;
        int cpus, err = -1;
@@ -3661,13 +3661,14 @@ SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
  * @pid: the pid in question.
  * @uattr: structure containing the extended parameters.
  */
-SYSCALL_DEFINE2(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr)
+SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,
+                              unsigned int, flags)
 {
        struct sched_attr attr;
        struct task_struct *p;
        int retval;
 
-       if (!uattr || pid < 0)
+       if (!uattr || pid < 0 || flags)
                return -EINVAL;
 
        if (sched_copy_attr(uattr, &attr))
@@ -3786,7 +3787,7 @@ static int sched_read_attr(struct sched_attr __user *uattr,
                attr->size = usize;
        }
 
-       ret = copy_to_user(uattr, attr, usize);
+       ret = copy_to_user(uattr, attr, attr->size);
        if (ret)
                return -EFAULT;
 
@@ -3804,8 +3805,8 @@ err_size:
  * @uattr: structure containing the extended parameters.
  * @size: sizeof(attr) for fwd/bwd comp.
  */
-SYSCALL_DEFINE3(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
-               unsigned int, size)
+SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
+               unsigned int, size, unsigned int, flags)
 {
        struct sched_attr attr = {
                .size = sizeof(struct sched_attr),
@@ -3814,7 +3815,7 @@ SYSCALL_DEFINE3(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
        int retval;
 
        if (!uattr || pid < 0 || size > PAGE_SIZE ||
-           size < SCHED_ATTR_SIZE_VER0)
+           size < SCHED_ATTR_SIZE_VER0 || flags)
                return -EINVAL;
 
        rcu_read_lock();
@@ -7422,6 +7423,7 @@ static int sched_dl_global_constraints(void)
        u64 period = global_rt_period();
        u64 new_bw = to_ratio(period, runtime);
        int cpu, ret = 0;
+       unsigned long flags;
 
        /*
         * Here we want to check the bandwidth not being set to some
@@ -7435,10 +7437,10 @@ static int sched_dl_global_constraints(void)
        for_each_possible_cpu(cpu) {
                struct dl_bw *dl_b = dl_bw_of(cpu);
 
-               raw_spin_lock(&dl_b->lock);
+               raw_spin_lock_irqsave(&dl_b->lock, flags);
                if (new_bw < dl_b->total_bw)
                        ret = -EBUSY;
-               raw_spin_unlock(&dl_b->lock);
+               raw_spin_unlock_irqrestore(&dl_b->lock, flags);
 
                if (ret)
                        break;
@@ -7451,6 +7453,7 @@ static void sched_dl_do_global(void)
 {
        u64 new_bw = -1;
        int cpu;
+       unsigned long flags;
 
        def_dl_bandwidth.dl_period = global_rt_period();
        def_dl_bandwidth.dl_runtime = global_rt_runtime();
@@ -7464,9 +7467,9 @@ static void sched_dl_do_global(void)
        for_each_possible_cpu(cpu) {
                struct dl_bw *dl_b = dl_bw_of(cpu);
 
-               raw_spin_lock(&dl_b->lock);
+               raw_spin_lock_irqsave(&dl_b->lock, flags);
                dl_b->bw = new_bw;
-               raw_spin_unlock(&dl_b->lock);
+               raw_spin_unlock_irqrestore(&dl_b->lock, flags);
        }
 }
 
@@ -7475,7 +7478,8 @@ static int sched_rt_global_validate(void)
        if (sysctl_sched_rt_period <= 0)
                return -EINVAL;
 
-       if (sysctl_sched_rt_runtime > sysctl_sched_rt_period)
+       if ((sysctl_sched_rt_runtime != RUNTIME_INF) &&
+               (sysctl_sched_rt_runtime > sysctl_sched_rt_period))
                return -EINVAL;
 
        return 0;
index 045fc74e3f0928fd73e1924b5b678f7d56654613..5b9bb42b2d47e760f3a7cd17af24ba37d2cf07ea 100644 (file)
@@ -70,7 +70,7 @@ static void cpudl_heapify(struct cpudl *cp, int idx)
 
 static void cpudl_change_key(struct cpudl *cp, int idx, u64 new_dl)
 {
-       WARN_ON(idx > num_present_cpus() || idx == IDX_INVALID);
+       WARN_ON(idx == IDX_INVALID || !cpu_present(idx));
 
        if (dl_time_before(new_dl, cp->elements[idx].dl)) {
                cp->elements[idx].dl = new_dl;
@@ -117,7 +117,7 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p,
        }
 
 out:
-       WARN_ON(best_cpu > num_present_cpus() && best_cpu != -1);
+       WARN_ON(best_cpu != -1 && !cpu_present(best_cpu));
 
        return best_cpu;
 }
@@ -137,7 +137,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid)
        int old_idx, new_cpu;
        unsigned long flags;
 
-       WARN_ON(cpu > num_present_cpus());
+       WARN_ON(!cpu_present(cpu));
 
        raw_spin_lock_irqsave(&cp->lock, flags);
        old_idx = cp->cpu_to_idx[cpu];
index 0dd5e0971a0778a3e09ee8a91f5851dfa1dc25a9..6e79b3faa4cd5384754232dc3b74300367afec8e 100644 (file)
@@ -121,7 +121,7 @@ static inline void dl_clear_overload(struct rq *rq)
 
 static void update_dl_migration(struct dl_rq *dl_rq)
 {
-       if (dl_rq->dl_nr_migratory && dl_rq->dl_nr_total > 1) {
+       if (dl_rq->dl_nr_migratory && dl_rq->dl_nr_running > 1) {
                if (!dl_rq->overloaded) {
                        dl_set_overload(rq_of_dl_rq(dl_rq));
                        dl_rq->overloaded = 1;
@@ -135,9 +135,7 @@ static void update_dl_migration(struct dl_rq *dl_rq)
 static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 {
        struct task_struct *p = dl_task_of(dl_se);
-       dl_rq = &rq_of_dl_rq(dl_rq)->dl;
 
-       dl_rq->dl_nr_total++;
        if (p->nr_cpus_allowed > 1)
                dl_rq->dl_nr_migratory++;
 
@@ -147,9 +145,7 @@ static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 static void dec_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 {
        struct task_struct *p = dl_task_of(dl_se);
-       dl_rq = &rq_of_dl_rq(dl_rq)->dl;
 
-       dl_rq->dl_nr_total--;
        if (p->nr_cpus_allowed > 1)
                dl_rq->dl_nr_migratory--;
 
@@ -566,6 +562,8 @@ int dl_runtime_exceeded(struct rq *rq, struct sched_dl_entity *dl_se)
        return 1;
 }
 
+extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq);
+
 /*
  * Update the current task's runtime statistics (provided it is still
  * a -deadline task and has not been removed from the dl_rq).
@@ -629,11 +627,13 @@ static void update_curr_dl(struct rq *rq)
                struct rt_rq *rt_rq = &rq->rt;
 
                raw_spin_lock(&rt_rq->rt_runtime_lock);
-               rt_rq->rt_time += delta_exec;
                /*
                 * We'll let actual RT tasks worry about the overflow here, we
-                * have our own CBS to keep us inline -- see above.
+                * have our own CBS to keep us inline; only account when RT
+                * bandwidth is relevant.
                 */
+               if (sched_rt_bandwidth_account(rt_rq))
+                       rt_rq->rt_time += delta_exec;
                raw_spin_unlock(&rt_rq->rt_runtime_lock);
        }
 }
@@ -717,6 +717,7 @@ void inc_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 
        WARN_ON(!dl_prio(prio));
        dl_rq->dl_nr_running++;
+       inc_nr_running(rq_of_dl_rq(dl_rq));
 
        inc_dl_deadline(dl_rq, deadline);
        inc_dl_migration(dl_se, dl_rq);
@@ -730,6 +731,7 @@ void dec_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
        WARN_ON(!dl_prio(prio));
        WARN_ON(!dl_rq->dl_nr_running);
        dl_rq->dl_nr_running--;
+       dec_nr_running(rq_of_dl_rq(dl_rq));
 
        dec_dl_deadline(dl_rq, dl_se->deadline);
        dec_dl_migration(dl_se, dl_rq);
@@ -836,8 +838,6 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
 
        if (!task_current(rq, p) && p->nr_cpus_allowed > 1)
                enqueue_pushable_dl_task(rq, p);
-
-       inc_nr_running(rq);
 }
 
 static void __dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags)
@@ -850,8 +850,6 @@ static void dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags)
 {
        update_curr_dl(rq);
        __dequeue_task_dl(rq, p, flags);
-
-       dec_nr_running(rq);
 }
 
 /*
index 966cc2bfcb77586d2ce9c55986aae2a3f2dce521..9b4c4f3201301a269bd66718650899274f204bc6 100644 (file)
@@ -1757,6 +1757,8 @@ void task_numa_work(struct callback_head *work)
                        start = end;
                        if (pages <= 0)
                                goto out;
+
+                       cond_resched();
                } while (end != vma->vm_end);
        }
 
@@ -6999,15 +7001,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
        struct cfs_rq *cfs_rq = cfs_rq_of(se);
 
        /*
-        * Ensure the task's vruntime is normalized, so that when its
+        * Ensure the task's vruntime is normalized, so that when it's
         * switched back to the fair class the enqueue_entity(.flags=0) will
         * do the right thing.
         *
-        * If it was on_rq, then the dequeue_entity(.flags=0) will already
-        * have normalized the vruntime, if it was !on_rq, then only when
+        * If it's on_rq, then the dequeue_entity(.flags=0) will already
+        * have normalized the vruntime, if it's !on_rq, then only when
         * the task is sleeping will it still have non-normalized vruntime.
         */
-       if (!se->on_rq && p->state != TASK_RUNNING) {
+       if (!p->on_rq && p->state != TASK_RUNNING) {
                /*
                 * Fix up our vruntime so that the current sleep doesn't
                 * cause 'unlimited' sleep bonus.
index a2740b775b456ed27c56ad088007c83e1873458b..1999021042c7010c6e5e86539b9c0b9a03519dcd 100644 (file)
@@ -538,6 +538,14 @@ static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq)
 
 #endif /* CONFIG_RT_GROUP_SCHED */
 
+bool sched_rt_bandwidth_account(struct rt_rq *rt_rq)
+{
+       struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
+
+       return (hrtimer_active(&rt_b->rt_period_timer) ||
+               rt_rq->rt_time < rt_b->rt_runtime);
+}
+
 #ifdef CONFIG_SMP
 /*
  * We ran out of runtime, see if we can borrow some from our neighbours.
index c2119fd20f8b6dc2042a80603d44223ab9365dec..f964add50f3863805f725e8fc13b447806f41022 100644 (file)
@@ -462,7 +462,6 @@ struct dl_rq {
        } earliest_dl;
 
        unsigned long dl_nr_migratory;
-       unsigned long dl_nr_total;
        int overloaded;
 
        /*
index 0abb364642818e4ef842ab2f3631d15cb80400f2..4d23dc4d8139988e13946ee48d37a76333c916c0 100644 (file)
@@ -116,20 +116,42 @@ static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
 void __init sched_clock_register(u64 (*read)(void), int bits,
                                 unsigned long rate)
 {
+       u64 res, wrap, new_mask, new_epoch, cyc, ns;
+       u32 new_mult, new_shift;
+       ktime_t new_wrap_kt;
        unsigned long r;
-       u64 res, wrap;
        char r_unit;
 
        if (cd.rate > rate)
                return;
 
        WARN_ON(!irqs_disabled());
-       read_sched_clock = read;
-       sched_clock_mask = CLOCKSOURCE_MASK(bits);
-       cd.rate = rate;
 
        /* calculate the mult/shift to convert counter ticks to ns. */
-       clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 3600);
+       clocks_calc_mult_shift(&new_mult, &new_shift, rate, NSEC_PER_SEC, 3600);
+
+       new_mask = CLOCKSOURCE_MASK(bits);
+
+       /* calculate how many ns until we wrap */
+       wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask);
+       new_wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
+
+       /* update epoch for new counter and update epoch_ns from old counter*/
+       new_epoch = read();
+       cyc = read_sched_clock();
+       ns = cd.epoch_ns + cyc_to_ns((cyc - cd.epoch_cyc) & sched_clock_mask,
+                         cd.mult, cd.shift);
+
+       raw_write_seqcount_begin(&cd.seq);
+       read_sched_clock = read;
+       sched_clock_mask = new_mask;
+       cd.rate = rate;
+       cd.wrap_kt = new_wrap_kt;
+       cd.mult = new_mult;
+       cd.shift = new_shift;
+       cd.epoch_cyc = new_epoch;
+       cd.epoch_ns = ns;
+       raw_write_seqcount_end(&cd.seq);
 
        r = rate;
        if (r >= 4000000) {
@@ -141,22 +163,12 @@ void __init sched_clock_register(u64 (*read)(void), int bits,
        } else
                r_unit = ' ';
 
-       /* calculate how many ns until we wrap */
-       wrap = clocks_calc_max_nsecs(cd.mult, cd.shift, 0, sched_clock_mask);
-       cd.wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
-
        /* calculate the ns resolution of this counter */
-       res = cyc_to_ns(1ULL, cd.mult, cd.shift);
+       res = cyc_to_ns(1ULL, new_mult, new_shift);
+
        pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n",
                bits, r, r_unit, res, wrap);
 
-       update_sched_clock();
-
-       /*
-        * Ensure that sched_clock() starts off at 0ns
-        */
-       cd.epoch_ns = 0;
-
        /* Enable IRQ time accounting if we have a fast enough sched_clock */
        if (irqtime > 0 || (irqtime == -1 && rate >= 1000000))
                enable_sched_clock_irqtime();
index e71ffd4eccb5b4d7a7b0234dd72e525b1c647550..f3989ceb5cd5aa7cbfae069015e8d915d6eb4c59 100644 (file)
@@ -1777,6 +1777,16 @@ static void trace_module_add_events(struct module *mod)
 {
        struct ftrace_event_call **call, **start, **end;
 
+       if (!mod->num_trace_events)
+               return;
+
+       /* Don't add infrastructure for mods without tracepoints */
+       if (trace_module_has_bad_taint(mod)) {
+               pr_err("%s: module has bad taint, not creating trace events\n",
+                      mod->name);
+               return;
+       }
+
        start = mod->trace_events;
        end = mod->trace_events + mod->num_trace_events;
 
index 29f26540e9c9550fd1c099512e7b20beb21ce234..031cc5655a514d2bcf89f930388dcddda396986f 100644 (file)
@@ -631,6 +631,11 @@ void tracepoint_iter_reset(struct tracepoint_iter *iter)
 EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
 
 #ifdef CONFIG_MODULES
+bool trace_module_has_bad_taint(struct module *mod)
+{
+       return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP));
+}
+
 static int tracepoint_module_coming(struct module *mod)
 {
        struct tp_module *tp_mod, *iter;
@@ -641,7 +646,7 @@ static int tracepoint_module_coming(struct module *mod)
         * module headers (for forced load), to make sure we don't cause a crash.
         * Staging and out-of-tree GPL modules are fine.
         */
-       if (mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)))
+       if (trace_module_has_bad_taint(mod))
                return 0;
        mutex_lock(&tracepoints_mutex);
        tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL);
index 240fb62cf3945aa0f7b601b343db65312a42f345..dd06439b9c84fe80463121905339c41493710998 100644 (file)
@@ -225,7 +225,7 @@ static u32 map_id_up(struct uid_gid_map *map, u32 id)
  *
  *     When there is no mapping defined for the user-namespace uid
  *     pair INVALID_UID is returned.  Callers are expected to test
- *     for and handle handle INVALID_UID being returned.  INVALID_UID
+ *     for and handle INVALID_UID being returned.  INVALID_UID
  *     may be tested for using uid_valid().
  */
 kuid_t make_kuid(struct user_namespace *ns, uid_t uid)
index 82ef9f3b7473a81ef5004362c7281ae9f4aea82a..193e977a10eaeb6a7f9ca5927d08f558d68df434 100644 (file)
@@ -1851,6 +1851,12 @@ static void destroy_worker(struct worker *worker)
        if (worker->flags & WORKER_IDLE)
                pool->nr_idle--;
 
+       /*
+        * Once WORKER_DIE is set, the kworker may destroy itself at any
+        * point.  Pin to ensure the task stays until we're done with it.
+        */
+       get_task_struct(worker->task);
+
        list_del_init(&worker->entry);
        worker->flags |= WORKER_DIE;
 
@@ -1859,6 +1865,7 @@ static void destroy_worker(struct worker *worker)
        spin_unlock_irq(&pool->lock);
 
        kthread_stop(worker->task);
+       put_task_struct(worker->task);
        kfree(worker);
 
        spin_lock_irq(&pool->lock);
index 2defd1308b045c46389a6232391999914573deb6..98f2d7e91a9114e5e124e42bef00d7935708e521 100644 (file)
@@ -424,111 +424,134 @@ void debug_dma_dump_mappings(struct device *dev)
 EXPORT_SYMBOL(debug_dma_dump_mappings);
 
 /*
- * For each page mapped (initial page in the case of
- * dma_alloc_coherent/dma_map_{single|page}, or each page in a
- * scatterlist) insert into this tree using the pfn as the key. At
+ * For each mapping (initial cacheline in the case of
+ * dma_alloc_coherent/dma_map_page, initial cacheline in each page of a
+ * scatterlist, or the cacheline specified in dma_map_single) insert
+ * into this tree using the cacheline as the key. At
  * dma_unmap_{single|sg|page} or dma_free_coherent delete the entry.  If
- * the pfn already exists at insertion time add a tag as a reference
+ * the entry already exists at insertion time add a tag as a reference
  * count for the overlapping mappings.  For now, the overlap tracking
- * just ensures that 'unmaps' balance 'maps' before marking the pfn
- * idle, but we should also be flagging overlaps as an API violation.
+ * just ensures that 'unmaps' balance 'maps' before marking the
+ * cacheline idle, but we should also be flagging overlaps as an API
+ * violation.
  *
  * Memory usage is mostly constrained by the maximum number of available
  * dma-debug entries in that we need a free dma_debug_entry before
- * inserting into the tree.  In the case of dma_map_{single|page} and
- * dma_alloc_coherent there is only one dma_debug_entry and one pfn to
- * track per event.  dma_map_sg(), on the other hand,
- * consumes a single dma_debug_entry, but inserts 'nents' entries into
- * the tree.
+ * inserting into the tree.  In the case of dma_map_page and
+ * dma_alloc_coherent there is only one dma_debug_entry and one
+ * dma_active_cacheline entry to track per event.  dma_map_sg(), on the
+ * other hand, consumes a single dma_debug_entry, but inserts 'nents'
+ * entries into the tree.
  *
  * At any time debug_dma_assert_idle() can be called to trigger a
- * warning if the given page is in the active set.
+ * warning if any cachelines in the given page are in the active set.
  */
-static RADIX_TREE(dma_active_pfn, GFP_NOWAIT);
+static RADIX_TREE(dma_active_cacheline, GFP_NOWAIT);
 static DEFINE_SPINLOCK(radix_lock);
-#define ACTIVE_PFN_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
+#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
+#define CACHELINE_PER_PAGE_SHIFT (PAGE_SHIFT - L1_CACHE_SHIFT)
+#define CACHELINES_PER_PAGE (1 << CACHELINE_PER_PAGE_SHIFT)
 
-static int active_pfn_read_overlap(unsigned long pfn)
+static phys_addr_t to_cacheline_number(struct dma_debug_entry *entry)
+{
+       return (entry->pfn << CACHELINE_PER_PAGE_SHIFT) +
+               (entry->offset >> L1_CACHE_SHIFT);
+}
+
+static int active_cacheline_read_overlap(phys_addr_t cln)
 {
        int overlap = 0, i;
 
        for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
-               if (radix_tree_tag_get(&dma_active_pfn, pfn, i))
+               if (radix_tree_tag_get(&dma_active_cacheline, cln, i))
                        overlap |= 1 << i;
        return overlap;
 }
 
-static int active_pfn_set_overlap(unsigned long pfn, int overlap)
+static int active_cacheline_set_overlap(phys_addr_t cln, int overlap)
 {
        int i;
 
-       if (overlap > ACTIVE_PFN_MAX_OVERLAP || overlap < 0)
+       if (overlap > ACTIVE_CACHELINE_MAX_OVERLAP || overlap < 0)
                return overlap;
 
        for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
                if (overlap & 1 << i)
-                       radix_tree_tag_set(&dma_active_pfn, pfn, i);
+                       radix_tree_tag_set(&dma_active_cacheline, cln, i);
                else
-                       radix_tree_tag_clear(&dma_active_pfn, pfn, i);
+                       radix_tree_tag_clear(&dma_active_cacheline, cln, i);
 
        return overlap;
 }
 
-static void active_pfn_inc_overlap(unsigned long pfn)
+static void active_cacheline_inc_overlap(phys_addr_t cln)
 {
-       int overlap = active_pfn_read_overlap(pfn);
+       int overlap = active_cacheline_read_overlap(cln);
 
-       overlap = active_pfn_set_overlap(pfn, ++overlap);
+       overlap = active_cacheline_set_overlap(cln, ++overlap);
 
        /* If we overflowed the overlap counter then we're potentially
         * leaking dma-mappings.  Otherwise, if maps and unmaps are
         * balanced then this overflow may cause false negatives in
-        * debug_dma_assert_idle() as the pfn may be marked idle
+        * debug_dma_assert_idle() as the cacheline may be marked idle
         * prematurely.
         */
-       WARN_ONCE(overlap > ACTIVE_PFN_MAX_OVERLAP,
-                 "DMA-API: exceeded %d overlapping mappings of pfn %lx\n",
-                 ACTIVE_PFN_MAX_OVERLAP, pfn);
+       WARN_ONCE(overlap > ACTIVE_CACHELINE_MAX_OVERLAP,
+                 "DMA-API: exceeded %d overlapping mappings of cacheline %pa\n",
+                 ACTIVE_CACHELINE_MAX_OVERLAP, &cln);
 }
 
-static int active_pfn_dec_overlap(unsigned long pfn)
+static int active_cacheline_dec_overlap(phys_addr_t cln)
 {
-       int overlap = active_pfn_read_overlap(pfn);
+       int overlap = active_cacheline_read_overlap(cln);
 
-       return active_pfn_set_overlap(pfn, --overlap);
+       return active_cacheline_set_overlap(cln, --overlap);
 }
 
-static int active_pfn_insert(struct dma_debug_entry *entry)
+static int active_cacheline_insert(struct dma_debug_entry *entry)
 {
+       phys_addr_t cln = to_cacheline_number(entry);
        unsigned long flags;
        int rc;
 
+       /* If the device is not writing memory then we don't have any
+        * concerns about the cpu consuming stale data.  This mitigates
+        * legitimate usages of overlapping mappings.
+        */
+       if (entry->direction == DMA_TO_DEVICE)
+               return 0;
+
        spin_lock_irqsave(&radix_lock, flags);
-       rc = radix_tree_insert(&dma_active_pfn, entry->pfn, entry);
+       rc = radix_tree_insert(&dma_active_cacheline, cln, entry);
        if (rc == -EEXIST)
-               active_pfn_inc_overlap(entry->pfn);
+               active_cacheline_inc_overlap(cln);
        spin_unlock_irqrestore(&radix_lock, flags);
 
        return rc;
 }
 
-static void active_pfn_remove(struct dma_debug_entry *entry)
+static void active_cacheline_remove(struct dma_debug_entry *entry)
 {
+       phys_addr_t cln = to_cacheline_number(entry);
        unsigned long flags;
 
+       /* ...mirror the insert case */
+       if (entry->direction == DMA_TO_DEVICE)
+               return;
+
        spin_lock_irqsave(&radix_lock, flags);
        /* since we are counting overlaps the final put of the
-        * entry->pfn will occur when the overlap count is 0.
-        * active_pfn_dec_overlap() returns -1 in that case
+        * cacheline will occur when the overlap count is 0.
+        * active_cacheline_dec_overlap() returns -1 in that case
         */
-       if (active_pfn_dec_overlap(entry->pfn) < 0)
-               radix_tree_delete(&dma_active_pfn, entry->pfn);
+       if (active_cacheline_dec_overlap(cln) < 0)
+               radix_tree_delete(&dma_active_cacheline, cln);
        spin_unlock_irqrestore(&radix_lock, flags);
 }
 
 /**
  * debug_dma_assert_idle() - assert that a page is not undergoing dma
- * @page: page to lookup in the dma_active_pfn tree
+ * @page: page to lookup in the dma_active_cacheline tree
  *
  * Place a call to this routine in cases where the cpu touching the page
  * before the dma completes (page is dma_unmapped) will lead to data
@@ -536,22 +559,38 @@ static void active_pfn_remove(struct dma_debug_entry *entry)
  */
 void debug_dma_assert_idle(struct page *page)
 {
+       static struct dma_debug_entry *ents[CACHELINES_PER_PAGE];
+       struct dma_debug_entry *entry = NULL;
+       void **results = (void **) &ents;
+       unsigned int nents, i;
        unsigned long flags;
-       struct dma_debug_entry *entry;
+       phys_addr_t cln;
 
        if (!page)
                return;
 
+       cln = (phys_addr_t) page_to_pfn(page) << CACHELINE_PER_PAGE_SHIFT;
        spin_lock_irqsave(&radix_lock, flags);
-       entry = radix_tree_lookup(&dma_active_pfn, page_to_pfn(page));
+       nents = radix_tree_gang_lookup(&dma_active_cacheline, results, cln,
+                                      CACHELINES_PER_PAGE);
+       for (i = 0; i < nents; i++) {
+               phys_addr_t ent_cln = to_cacheline_number(ents[i]);
+
+               if (ent_cln == cln) {
+                       entry = ents[i];
+                       break;
+               } else if (ent_cln >= cln + CACHELINES_PER_PAGE)
+                       break;
+       }
        spin_unlock_irqrestore(&radix_lock, flags);
 
        if (!entry)
                return;
 
+       cln = to_cacheline_number(entry);
        err_printk(entry->dev, entry,
-                  "DMA-API: cpu touching an active dma mapped page "
-                  "[pfn=0x%lx]\n", entry->pfn);
+                  "DMA-API: cpu touching an active dma mapped cacheline [cln=%pa]\n",
+                  &cln);
 }
 
 /*
@@ -568,9 +607,9 @@ static void add_dma_entry(struct dma_debug_entry *entry)
        hash_bucket_add(bucket, entry);
        put_hash_bucket(bucket, &flags);
 
-       rc = active_pfn_insert(entry);
+       rc = active_cacheline_insert(entry);
        if (rc == -ENOMEM) {
-               pr_err("DMA-API: pfn tracking ENOMEM, dma-debug disabled\n");
+               pr_err("DMA-API: cacheline tracking ENOMEM, dma-debug disabled\n");
                global_disable = true;
        }
 
@@ -631,7 +670,7 @@ static void dma_entry_free(struct dma_debug_entry *entry)
 {
        unsigned long flags;
 
-       active_pfn_remove(entry);
+       active_cacheline_remove(entry);
 
        /*
         * add to beginning of the list - this way the entries are
index 7811ed3b4e701c2e0d82368a8bae457279ca3246..bd4a8dfdf0b8052cdaedd0b3478eea4138ac100a 100644 (file)
@@ -1253,8 +1253,10 @@ unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item)
 
                node = indirect_to_ptr(node);
                max_index = radix_tree_maxindex(node->height);
-               if (cur_index > max_index)
+               if (cur_index > max_index) {
+                       rcu_read_unlock();
                        break;
+               }
 
                cur_index = __locate(node, item, cur_index, &found_index);
                rcu_read_unlock();
index 2d9f1504d75e26d45ddf58fe2db8c048ecbc8d83..2888024e0b0abea6b6f37f4531ad0f8dfec5c7b3 100644 (file)
@@ -575,5 +575,5 @@ config PGTABLE_MAPPING
          then you should select this. This causes zsmalloc to use page table
          mapping rather than copying for object mapping.
 
-         You can check speed with zsmalloc benchmark[1].
-         [1] https://github.com/spartacus06/zsmalloc
+         You can check speed with zsmalloc benchmark:
+         https://github.com/spartacus06/zsmapbench
index b48c5259ea33dfed9e4c08c956d8e30a36480c42..918577595ea8695298cd21ecab7acaca35b1eb92 100644 (file)
@@ -251,7 +251,6 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 {
        int nr_scanned = 0, total_isolated = 0;
        struct page *cursor, *valid_page = NULL;
-       unsigned long nr_strict_required = end_pfn - blockpfn;
        unsigned long flags;
        bool locked = false;
 
@@ -264,11 +263,12 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 
                nr_scanned++;
                if (!pfn_valid_within(blockpfn))
-                       continue;
+                       goto isolate_fail;
+
                if (!valid_page)
                        valid_page = page;
                if (!PageBuddy(page))
-                       continue;
+                       goto isolate_fail;
 
                /*
                 * The zone lock must be held to isolate freepages.
@@ -289,12 +289,10 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 
                /* Recheck this is a buddy page under lock */
                if (!PageBuddy(page))
-                       continue;
+                       goto isolate_fail;
 
                /* Found a free page, break it into order-0 pages */
                isolated = split_free_page(page);
-               if (!isolated && strict)
-                       break;
                total_isolated += isolated;
                for (i = 0; i < isolated; i++) {
                        list_add(&page->lru, freelist);
@@ -305,7 +303,15 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
                if (isolated) {
                        blockpfn += isolated - 1;
                        cursor += isolated - 1;
+                       continue;
                }
+
+isolate_fail:
+               if (strict)
+                       break;
+               else
+                       continue;
+
        }
 
        trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated);
@@ -315,7 +321,7 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
         * pages requested were isolated. If there were any failures, 0 is
         * returned and CMA will fail.
         */
-       if (strict && nr_strict_required > total_isolated)
+       if (strict && blockpfn < end_pfn)
                total_isolated = 0;
 
        if (locked)
index da23eb96779f2bfb4e893eece4774f14499ebaaa..1546655a2d78afe4dc1c954b5e0ccff77ba3437f 100644 (file)
@@ -1166,8 +1166,10 @@ alloc:
                } else {
                        ret = do_huge_pmd_wp_page_fallback(mm, vma, address,
                                        pmd, orig_pmd, page, haddr);
-                       if (ret & VM_FAULT_OOM)
+                       if (ret & VM_FAULT_OOM) {
                                split_huge_page(page);
+                               ret |= VM_FAULT_FALLBACK;
+                       }
                        put_page(page);
                }
                count_vm_event(THP_FAULT_FALLBACK);
@@ -1179,9 +1181,10 @@ alloc:
                if (page) {
                        split_huge_page(page);
                        put_page(page);
-               }
+               } else
+                       split_huge_page_pmd(vma, address, pmd);
+               ret |= VM_FAULT_FALLBACK;
                count_vm_event(THP_FAULT_FALLBACK);
-               ret |= VM_FAULT_OOM;
                goto out;
        }
 
@@ -1958,7 +1961,7 @@ out:
        return ret;
 }
 
-#define VM_NO_THP (VM_SPECIAL|VM_MIXEDMAP|VM_HUGETLB|VM_SHARED|VM_MAYSHARE)
+#define VM_NO_THP (VM_SPECIAL | VM_HUGETLB | VM_SHARED | VM_MAYSHARE)
 
 int hugepage_madvise(struct vm_area_struct *vma,
                     unsigned long *vm_flags, int advice)
index aa4c7c7250c11a95b9676b70c7cc38f987d88717..68710e80994afed815c58b59a1a3cf421df8101f 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -444,7 +444,7 @@ static void break_cow(struct rmap_item *rmap_item)
 static struct page *page_trans_compound_anon(struct page *page)
 {
        if (PageTransCompound(page)) {
-               struct page *head = compound_trans_head(page);
+               struct page *head = compound_head(page);
                /*
                 * head may actually be splitted and freed from under
                 * us but it's ok here.
index 53385cd4e6f02cfae85f99a2629f735094130c78..5b6b0039f725032de5d63376aa0388e49bd3192d 100644 (file)
@@ -1127,8 +1127,8 @@ skip_node:
         * skipping css reference should be safe.
         */
        if (next_css) {
-               if ((next_css->flags & CSS_ONLINE) &&
-                               (next_css == &root->css || css_tryget(next_css)))
+               if ((next_css == &root->css) ||
+                   ((next_css->flags & CSS_ONLINE) && css_tryget(next_css)))
                        return mem_cgroup_from_css(next_css);
 
                prev_css = next_css;
@@ -1687,7 +1687,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
         * protects memcg_name and makes sure that parallel ooms do not
         * interleave
         */
-       static DEFINE_SPINLOCK(oom_info_lock);
+       static DEFINE_MUTEX(oom_info_lock);
        struct cgroup *task_cgrp;
        struct cgroup *mem_cgrp;
        static char memcg_name[PATH_MAX];
@@ -1698,7 +1698,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
        if (!p)
                return;
 
-       spin_lock(&oom_info_lock);
+       mutex_lock(&oom_info_lock);
        rcu_read_lock();
 
        mem_cgrp = memcg->css.cgroup;
@@ -1767,7 +1767,7 @@ done:
 
                pr_cont("\n");
        }
-       spin_unlock(&oom_info_lock);
+       mutex_unlock(&oom_info_lock);
 }
 
 /*
@@ -6595,6 +6595,7 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(css);
        struct mem_cgroup_event *event, *tmp;
+       struct cgroup_subsys_state *iter;
 
        /*
         * Unregister events and notify userspace.
@@ -6611,7 +6612,14 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
        kmem_cgroup_css_offline(memcg);
 
        mem_cgroup_invalidate_reclaim_iterators(memcg);
-       mem_cgroup_reparent_charges(memcg);
+
+       /*
+        * This requires that offlining is serialized.  Right now that is
+        * guaranteed because css_killed_work_fn() holds the cgroup_mutex.
+        */
+       css_for_each_descendant_post(iter, css)
+               mem_cgroup_reparent_charges(mem_cgroup_from_css(iter));
+
        mem_cgroup_destroy_all_caches(memcg);
        vmpressure_cleanup(&memcg->vmpressure);
 }
index 2f2f34a4e77de18e47bc815e3fd90ace33967e55..90002ea43638cd0dd669d12092837714ec3113f3 100644 (file)
@@ -1651,7 +1651,7 @@ int soft_offline_page(struct page *page, int flags)
 {
        int ret;
        unsigned long pfn = page_to_pfn(page);
-       struct page *hpage = compound_trans_head(page);
+       struct page *hpage = compound_head(page);
 
        if (PageHWPoison(page)) {
                pr_info("soft offline: %#lx page already poisoned\n", pfn);
index be6a0c0d4ae081d48edd26f09d37f67cc70b1c52..22dfa617bddb69af777298c45739a0113f965b13 100644 (file)
@@ -3348,6 +3348,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                if (ret & VM_FAULT_LOCKED)
                        unlock_page(vmf.page);
                ret = VM_FAULT_HWPOISON;
+               page_cache_release(vmf.page);
                goto uncharge_out;
        }
 
@@ -3703,7 +3704,6 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        if (unlikely(is_vm_hugetlb_page(vma)))
                return hugetlb_fault(mm, vma, address, flags);
 
-retry:
        pgd = pgd_offset(mm, address);
        pud = pud_alloc(mm, pgd, address);
        if (!pud)
@@ -3741,20 +3741,13 @@ retry:
                        if (dirty && !pmd_write(orig_pmd)) {
                                ret = do_huge_pmd_wp_page(mm, vma, address, pmd,
                                                          orig_pmd);
-                               /*
-                                * If COW results in an oom, the huge pmd will
-                                * have been split, so retry the fault on the
-                                * pte for a smaller charge.
-                                */
-                               if (unlikely(ret & VM_FAULT_OOM))
-                                       goto retry;
-                               return ret;
+                               if (!(ret & VM_FAULT_FALLBACK))
+                                       return ret;
                        } else {
                                huge_pmd_set_accessed(mm, vma, address, pmd,
                                                      orig_pmd, dirty);
+                               return 0;
                        }
-
-                       return 0;
                }
        }
 
index 482a33d89134fd83e15d5f6863dae57f5cb05aac..b494fdb9a6363e058f802069ba5de8e677005b45 100644 (file)
@@ -1158,7 +1158,7 @@ static struct page *new_page_node(struct page *p, unsigned long private,
                                        pm->node);
        else
                return alloc_pages_exact_node(pm->node,
-                               GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0);
+                               GFP_HIGHUSER_MOVABLE | __GFP_THISNODE, 0);
 }
 
 /*
@@ -1544,9 +1544,9 @@ static struct page *alloc_misplaced_dst_page(struct page *page,
        struct page *newpage;
 
        newpage = alloc_pages_exact_node(nid,
-                                        (GFP_HIGHUSER_MOVABLE | GFP_THISNODE |
-                                         __GFP_NOMEMALLOC | __GFP_NORETRY |
-                                         __GFP_NOWARN) &
+                                        (GFP_HIGHUSER_MOVABLE |
+                                         __GFP_THISNODE | __GFP_NOMEMALLOC |
+                                         __GFP_NORETRY | __GFP_NOWARN) &
                                         ~GFP_IOFS, 0);
 
        return newpage;
@@ -1747,7 +1747,8 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
                goto out_dropref;
 
        new_page = alloc_pages_node(node,
-               (GFP_TRANSHUGE | GFP_THISNODE) & ~__GFP_WAIT, HPAGE_PMD_ORDER);
+               (GFP_TRANSHUGE | __GFP_THISNODE) & ~__GFP_WAIT,
+               HPAGE_PMD_ORDER);
        if (!new_page)
                goto out_fail;
 
index e3758a09a009747bd17cb75442d0fcae69a74cc4..3bac76ae4b30ec8a62042bdff9644e87ee181d3c 100644 (file)
@@ -369,9 +369,11 @@ void prep_compound_page(struct page *page, unsigned long order)
        __SetPageHead(page);
        for (i = 1; i < nr_pages; i++) {
                struct page *p = page + i;
-               __SetPageTail(p);
                set_page_count(p, 0);
                p->first_page = page;
+               /* Make sure p->first_page is always valid for PageTail() */
+               smp_wmb();
+               __SetPageTail(p);
        }
 }
 
@@ -1236,6 +1238,15 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
        }
        local_irq_restore(flags);
 }
+static bool gfp_thisnode_allocation(gfp_t gfp_mask)
+{
+       return (gfp_mask & GFP_THISNODE) == GFP_THISNODE;
+}
+#else
+static bool gfp_thisnode_allocation(gfp_t gfp_mask)
+{
+       return false;
+}
 #endif
 
 /*
@@ -1572,7 +1583,13 @@ again:
                                          get_pageblock_migratetype(page));
        }
 
-       __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
+       /*
+        * NOTE: GFP_THISNODE allocations do not partake in the kswapd
+        * aging protocol, so they can't be fair.
+        */
+       if (!gfp_thisnode_allocation(gfp_flags))
+               __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
+
        __count_zone_vm_events(PGALLOC, zone, 1 << order);
        zone_statistics(preferred_zone, zone, gfp_flags);
        local_irq_restore(flags);
@@ -1944,8 +1961,12 @@ zonelist_scan:
                 * ultimately fall back to remote zones that do not
                 * partake in the fairness round-robin cycle of this
                 * zonelist.
+                *
+                * NOTE: GFP_THISNODE allocations do not partake in
+                * the kswapd aging protocol, so they can't be fair.
                 */
-               if (alloc_flags & ALLOC_WMARK_LOW) {
+               if ((alloc_flags & ALLOC_WMARK_LOW) &&
+                   !gfp_thisnode_allocation(gfp_mask)) {
                        if (zone_page_state(zone, NR_ALLOC_BATCH) <= 0)
                                continue;
                        if (!zone_local(preferred_zone, zone))
@@ -2501,8 +2522,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
         * allowed per node queues are empty and that nodes are
         * over allocated.
         */
-       if (IS_ENABLED(CONFIG_NUMA) &&
-                       (gfp_mask & GFP_THISNODE) == GFP_THISNODE)
+       if (gfp_thisnode_allocation(gfp_mask))
                goto nopage;
 
 restart:
index b31ba67d440ac997a05de372e831046bf98d9070..0092097b3f4ce5e22844759a9e264ef143d05c7c 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -98,7 +98,7 @@ static void put_compound_page(struct page *page)
        }
 
        /* __split_huge_page_refcount can run under us */
-       page_head = compound_trans_head(page);
+       page_head = compound_head(page);
 
        /*
         * THP can not break up slab pages so avoid taking
@@ -253,7 +253,7 @@ bool __get_page_tail(struct page *page)
         */
        unsigned long flags;
        bool got;
-       struct page *page_head = compound_trans_head(page);
+       struct page *page_head = compound_head(page);
 
        /* Ref to put_compound_page() comment. */
        if (!__compound_tail_refcounted(page_head)) {
index 196970a4541f0c07108eff49b7cb8d12fd930b06..d4042e75f7c7e7c7d498c4fcc33c90f1d1de2bff 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 #include <linux/vmstat.h>
 #include <linux/eventfd.h>
+#include <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/printk.h>
 #include <linux/vmpressure.h>
index 5704ed9c3a23bb13d1d5b41f36d6575fd3ec3ed9..9d010a09ab9880a6eb15cee0524b46be53d76587 100644 (file)
@@ -38,9 +38,9 @@ struct vlan_info {
 static inline unsigned int vlan_proto_idx(__be16 proto)
 {
        switch (proto) {
-       case __constant_htons(ETH_P_8021Q):
+       case htons(ETH_P_8021Q):
                return VLAN_PROTO_8021Q;
-       case __constant_htons(ETH_P_8021AD):
+       case htons(ETH_P_8021AD):
                return VLAN_PROTO_8021AD;
        default:
                BUG();
index 6ee48aac776fbe84db68a503d9aca10ca45b0081..35b3c192d7b90b97faaa684868b75fec47d200f7 100644 (file)
@@ -22,11 +22,11 @@ bool vlan_do_receive(struct sk_buff **skbp)
                return false;
 
        skb->dev = vlan_dev;
-       if (skb->pkt_type == PACKET_OTHERHOST) {
+       if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) {
                /* Our lower layer thinks this is not local, let's make sure.
                 * This allows the VLAN to have a different MAC than the
                 * underlying device, and still route correctly. */
-               if (ether_addr_equal(eth_hdr(skb)->h_dest, vlan_dev->dev_addr))
+               if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, vlan_dev->dev_addr))
                        skb->pkt_type = PACKET_HOST;
        }
 
index 566adbf5c5067764b704c8f1d8dec3361227d370..4f3e9073cb49860cf35ac8cd2c17b147d67432d7 100644 (file)
@@ -538,6 +538,9 @@ static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev
        struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
        struct net_device *real_dev = vlan->real_dev;
 
+       if (saddr == NULL)
+               saddr = dev->dev_addr;
+
        return dev_hard_header(skb, real_dev, type, daddr, saddr, len);
 }
 
@@ -675,13 +678,13 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st
 
                        p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i);
                        do {
-                               start = u64_stats_fetch_begin_bh(&p->syncp);
+                               start = u64_stats_fetch_begin_irq(&p->syncp);
                                rxpackets       = p->rx_packets;
                                rxbytes         = p->rx_bytes;
                                rxmulticast     = p->rx_multicast;
                                txpackets       = p->tx_packets;
                                txbytes         = p->tx_bytes;
-                       } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                        stats->rx_packets       += rxpackets;
                        stats->rx_bytes         += rxbytes;
index c7e634af85165613822074b28ceeca4af7153ae7..8ac8a5cc214331253e591fe26f6c3b39a00d5023 100644 (file)
@@ -56,8 +56,8 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
 
        if (data[IFLA_VLAN_PROTOCOL]) {
                switch (nla_get_be16(data[IFLA_VLAN_PROTOCOL])) {
-               case __constant_htons(ETH_P_8021Q):
-               case __constant_htons(ETH_P_8021AD):
+               case htons(ETH_P_8021Q):
+               case htons(ETH_P_8021AD):
                        break;
                default:
                        return -EPROTONOSUPPORT;
index adb3ea04adaaa73d3faf4db783f096e91e93321e..73492b91105ac0aba10aec738415128d0582bfc5 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "6lowpan.h"
 
-#include "../ieee802154/6lowpan.h" /* for the compression support */
+#include <net/6lowpan.h> /* for the compression support */
 
 #define IFACE_NAME_TEMPLATE "bt%d"
 #define EUI64_ADDR_LEN 8
index efcd108822c43134e3d64755e24c16410f0598d5..f986b9968bdb8845c6747e9f29205e03090627f7 100644 (file)
@@ -235,7 +235,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
                        BT_DBG("chan %p state %s", chan,
                               state_to_string(chan->state));
 
-                       if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
+                       if (chan->scid == L2CAP_CID_A2MP)
                                continue;
 
                        l2cap_chan_lock(chan);
@@ -726,7 +726,11 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
 
        BT_DBG("chan %p", chan);
 
-       chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
+       chan->chan_type = L2CAP_CHAN_FIXED;
+       chan->scid = L2CAP_CID_A2MP;
+       chan->dcid = L2CAP_CID_A2MP;
+       chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+       chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
        chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 
        chan->ops = &a2mp_chan_ops;
index 0c5866bb49b6fc8933b01d0e5ed0c9d3f8564c63..2021c481cdb657a8011938f5e8486c4c93f0c116 100644 (file)
@@ -31,7 +31,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <linux/proc_fs.h>
 
-#define VERSION "2.18"
+#define VERSION "2.19"
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO   8
index ba5366c320dacc7d4db4659aa144051baf1b035a..7c713c4675bafa7f6da02837daa2e2ae5f57becf 100644 (file)
@@ -225,13 +225,13 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
        cp.conn_interval_max    = cpu_to_le16(max);
        cp.conn_latency         = cpu_to_le16(latency);
        cp.supervision_timeout  = cpu_to_le16(to_multiplier);
-       cp.min_ce_len           = __constant_cpu_to_le16(0x0001);
-       cp.max_ce_len           = __constant_cpu_to_le16(0x0001);
+       cp.min_ce_len           = __constant_cpu_to_le16(0x0000);
+       cp.max_ce_len           = __constant_cpu_to_le16(0x0000);
 
        hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
 }
 
-void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
+void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
                      __u8 ltk[16])
 {
        struct hci_dev *hdev = conn->hdev;
@@ -242,9 +242,9 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
        memset(&cp, 0, sizeof(cp));
 
        cp.handle = cpu_to_le16(conn->handle);
-       memcpy(cp.ltk, ltk, sizeof(cp.ltk));
+       cp.rand = rand;
        cp.ediv = ediv;
-       memcpy(cp.rand, rand, sizeof(cp.rand));
+       memcpy(cp.ltk, ltk, sizeof(cp.ltk));
 
        hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
 }
@@ -363,6 +363,16 @@ static void hci_conn_auto_accept(struct work_struct *work)
                     &conn->dst);
 }
 
+static void le_conn_timeout(struct work_struct *work)
+{
+       struct hci_conn *conn = container_of(work, struct hci_conn,
+                                            le_conn_timeout.work);
+
+       BT_DBG("");
+
+       hci_le_create_connection_cancel(conn);
+}
+
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 {
        struct hci_conn *conn;
@@ -410,6 +420,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
        INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
        INIT_DELAYED_WORK(&conn->auto_accept_work, hci_conn_auto_accept);
        INIT_DELAYED_WORK(&conn->idle_work, hci_conn_idle);
+       INIT_DELAYED_WORK(&conn->le_conn_timeout, le_conn_timeout);
 
        atomic_set(&conn->refcnt, 0);
 
@@ -442,6 +453,8 @@ int hci_conn_del(struct hci_conn *conn)
                /* Unacked frames */
                hdev->acl_cnt += conn->sent;
        } else if (conn->type == LE_LINK) {
+               cancel_delayed_work_sync(&conn->le_conn_timeout);
+
                if (hdev->le_pkts)
                        hdev->le_cnt += conn->sent;
                else
@@ -514,6 +527,26 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 }
 EXPORT_SYMBOL(hci_get_route);
 
+/* This function requires the caller holds hdev->lock */
+void hci_le_conn_failed(struct hci_conn *conn, u8 status)
+{
+       struct hci_dev *hdev = conn->hdev;
+
+       conn->state = BT_CLOSED;
+
+       mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type,
+                           status);
+
+       hci_proto_connect_cfm(conn, status);
+
+       hci_conn_del(conn);
+
+       /* Since we may have temporarily stopped the background scanning in
+        * favor of connection establishment, we should restart it.
+        */
+       hci_update_background_scan(hdev);
+}
+
 static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
 {
        struct hci_conn *conn;
@@ -530,55 +563,55 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
        if (!conn)
                goto done;
 
-       conn->state = BT_CLOSED;
-
-       mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type,
-                           status);
-
-       hci_proto_connect_cfm(conn, status);
-
-       hci_conn_del(conn);
+       hci_le_conn_failed(conn, status);
 
 done:
        hci_dev_unlock(hdev);
 }
 
-static int hci_create_le_conn(struct hci_conn *conn)
+static void hci_req_add_le_create_conn(struct hci_request *req,
+                                      struct hci_conn *conn)
 {
-       struct hci_dev *hdev = conn->hdev;
        struct hci_cp_le_create_conn cp;
-       struct hci_request req;
-       int err;
-
-       hci_req_init(&req, hdev);
+       struct hci_dev *hdev = conn->hdev;
+       u8 own_addr_type;
 
        memset(&cp, 0, sizeof(cp));
+
+       /* Update random address, but set require_privacy to false so
+        * that we never connect with an unresolvable address.
+        */
+       if (hci_update_random_address(req, false, &own_addr_type))
+               return;
+
+       /* Save the address type used for this connnection attempt so we able
+        * to retrieve this information if we need it.
+        */
+       conn->src_type = own_addr_type;
+
        cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
        cp.scan_window = cpu_to_le16(hdev->le_scan_window);
        bacpy(&cp.peer_addr, &conn->dst);
        cp.peer_addr_type = conn->dst_type;
-       cp.own_address_type = conn->src_type;
-       cp.conn_interval_min = cpu_to_le16(hdev->le_conn_min_interval);
-       cp.conn_interval_max = cpu_to_le16(hdev->le_conn_max_interval);
+       cp.own_address_type = own_addr_type;
+       cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
+       cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
        cp.supervision_timeout = __constant_cpu_to_le16(0x002a);
        cp.min_ce_len = __constant_cpu_to_le16(0x0000);
        cp.max_ce_len = __constant_cpu_to_le16(0x0000);
 
-       hci_req_add(&req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
-
-       err = hci_req_run(&req, create_le_conn_complete);
-       if (err) {
-               hci_conn_del(conn);
-               return err;
-       }
+       hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
 
-       return 0;
+       conn->state = BT_CONNECT;
 }
 
-static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
-                                   u8 dst_type, u8 sec_level, u8 auth_type)
+struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
+                               u8 dst_type, u8 sec_level, u8 auth_type)
 {
+       struct hci_conn_params *params;
        struct hci_conn *conn;
+       struct smp_irk *irk;
+       struct hci_request req;
        int err;
 
        if (test_bit(HCI_ADVERTISING, &hdev->flags))
@@ -607,35 +640,74 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
        if (conn)
                return ERR_PTR(-EBUSY);
 
+       /* When given an identity address with existing identity
+        * resolving key, the connection needs to be established
+        * to a resolvable random address.
+        *
+        * This uses the cached random resolvable address from
+        * a previous scan. When no cached address is available,
+        * try connecting to the identity address instead.
+        *
+        * Storing the resolvable random address is required here
+        * to handle connection failures. The address will later
+        * be resolved back into the original identity address
+        * from the connect request.
+        */
+       irk = hci_find_irk_by_addr(hdev, dst, dst_type);
+       if (irk && bacmp(&irk->rpa, BDADDR_ANY)) {
+               dst = &irk->rpa;
+               dst_type = ADDR_LE_DEV_RANDOM;
+       }
+
        conn = hci_conn_add(hdev, LE_LINK, dst);
        if (!conn)
                return ERR_PTR(-ENOMEM);
 
-       if (dst_type == BDADDR_LE_PUBLIC)
-               conn->dst_type = ADDR_LE_DEV_PUBLIC;
-       else
-               conn->dst_type = ADDR_LE_DEV_RANDOM;
-
-       conn->src_type = hdev->own_addr_type;
+       conn->dst_type = dst_type;
 
-       conn->state = BT_CONNECT;
        conn->out = true;
        conn->link_mode |= HCI_LM_MASTER;
        conn->sec_level = BT_SECURITY_LOW;
        conn->pending_sec_level = sec_level;
        conn->auth_type = auth_type;
 
-       err = hci_create_le_conn(conn);
-       if (err)
+       params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
+       if (params) {
+               conn->le_conn_min_interval = params->conn_min_interval;
+               conn->le_conn_max_interval = params->conn_max_interval;
+       } else {
+               conn->le_conn_min_interval = hdev->le_conn_min_interval;
+               conn->le_conn_max_interval = hdev->le_conn_max_interval;
+       }
+
+       hci_req_init(&req, hdev);
+
+       /* If controller is scanning, we stop it since some controllers are
+        * not able to scan and connect at the same time. Also set the
+        * HCI_LE_SCAN_INTERRUPTED flag so that the command complete
+        * handler for scan disabling knows to set the correct discovery
+        * state.
+        */
+       if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
+               hci_req_add_le_scan_disable(&req);
+               set_bit(HCI_LE_SCAN_INTERRUPTED, &hdev->dev_flags);
+       }
+
+       hci_req_add_le_create_conn(&req, conn);
+
+       err = hci_req_run(&req, create_le_conn_complete);
+       if (err) {
+               hci_conn_del(conn);
                return ERR_PTR(err);
+       }
 
 done:
        hci_conn_hold(conn);
        return conn;
 }
 
-static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
-                                               u8 sec_level, u8 auth_type)
+struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
+                                u8 sec_level, u8 auth_type)
 {
        struct hci_conn *acl;
 
@@ -704,22 +776,6 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
        return sco;
 }
 
-/* Create SCO, ACL or LE connection. */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
-                            __u8 dst_type, __u8 sec_level, __u8 auth_type)
-{
-       BT_DBG("%s dst %pMR type 0x%x", hdev->name, dst, type);
-
-       switch (type) {
-       case LE_LINK:
-               return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type);
-       case ACL_LINK:
-               return hci_connect_acl(hdev, dst, sec_level, auth_type);
-       }
-
-       return ERR_PTR(-EINVAL);
-}
-
 /* Check link security requirement */
 int hci_conn_check_link_mode(struct hci_conn *conn)
 {
@@ -800,14 +856,23 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
        if (!(conn->link_mode & HCI_LM_AUTH))
                goto auth;
 
-       /* An authenticated combination key has sufficient security for any
-          security level. */
-       if (conn->key_type == HCI_LK_AUTH_COMBINATION)
+       /* An authenticated FIPS approved combination key has sufficient
+        * security for security level 4. */
+       if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256 &&
+           sec_level == BT_SECURITY_FIPS)
+               goto encrypt;
+
+       /* An authenticated combination key has sufficient security for
+          security level 3. */
+       if ((conn->key_type == HCI_LK_AUTH_COMBINATION_P192 ||
+            conn->key_type == HCI_LK_AUTH_COMBINATION_P256) &&
+           sec_level == BT_SECURITY_HIGH)
                goto encrypt;
 
        /* An unauthenticated combination key has sufficient security for
           security level 1 and 2. */
-       if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
+       if ((conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 ||
+            conn->key_type == HCI_LK_UNAUTH_COMBINATION_P256) &&
            (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW))
                goto encrypt;
 
@@ -816,7 +881,8 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
           is generated using maximum PIN code length (16).
           For pre 2.1 units. */
        if (conn->key_type == HCI_LK_COMBINATION &&
-           (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16))
+           (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW ||
+            conn->pin_length == 16))
                goto encrypt;
 
 auth:
@@ -840,13 +906,17 @@ int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level)
 {
        BT_DBG("hcon %p", conn);
 
-       if (sec_level != BT_SECURITY_HIGH)
-               return 1; /* Accept if non-secure is required */
+       /* Accept if non-secure or higher security level is required */
+       if (sec_level != BT_SECURITY_HIGH && sec_level != BT_SECURITY_FIPS)
+               return 1;
 
-       if (conn->sec_level == BT_SECURITY_HIGH)
+       /* Accept if secure or higher security level is already present */
+       if (conn->sec_level == BT_SECURITY_HIGH ||
+           conn->sec_level == BT_SECURITY_FIPS)
                return 1;
 
-       return 0; /* Reject not secure link */
+       /* Reject not secure link */
+       return 0;
 }
 EXPORT_SYMBOL(hci_conn_check_secure);
 
index 5e8663c194c18e3c29ab221efe667dd311944294..8bbfdea9cbec8825391169776c9891e9565d743f 100644 (file)
 #include <linux/idr.h>
 #include <linux/rfkill.h>
 #include <linux/debugfs.h>
+#include <linux/crypto.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
+#include "smp.h"
+
 static void hci_rx_work(struct work_struct *work);
 static void hci_cmd_work(struct work_struct *work);
 static void hci_tx_work(struct work_struct *work);
@@ -285,24 +288,6 @@ static const struct file_operations link_keys_fops = {
        .release        = single_release,
 };
 
-static ssize_t use_debug_keys_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_DEBUG_KEYS, &hdev->dev_flags) ? 'Y': 'N';
-       buf[1] = '\n';
-       buf[2] = '\0';
-       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
-}
-
-static const struct file_operations use_debug_keys_fops = {
-       .open           = simple_open,
-       .read           = use_debug_keys_read,
-       .llseek         = default_llseek,
-};
-
 static int dev_class_show(struct seq_file *f, void *ptr)
 {
        struct hci_dev *hdev = f->private;
@@ -415,6 +400,70 @@ static int ssp_debug_mode_get(void *data, u64 *val)
 DEFINE_SIMPLE_ATTRIBUTE(ssp_debug_mode_fops, ssp_debug_mode_get,
                        ssp_debug_mode_set, "%llu\n");
 
+static ssize_t force_sc_support_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_FORCE_SC, &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 force_sc_support_write(struct file *file,
+                                     const char __user *user_buf,
+                                     size_t count, loff_t *ppos)
+{
+       struct hci_dev *hdev = file->private_data;
+       char buf[32];
+       size_t buf_size = min(count, (sizeof(buf)-1));
+       bool enable;
+
+       if (test_bit(HCI_UP, &hdev->flags))
+               return -EBUSY;
+
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+       if (strtobool(buf, &enable))
+               return -EINVAL;
+
+       if (enable == test_bit(HCI_FORCE_SC, &hdev->dev_flags))
+               return -EALREADY;
+
+       change_bit(HCI_FORCE_SC, &hdev->dev_flags);
+
+       return count;
+}
+
+static const struct file_operations force_sc_support_fops = {
+       .open           = simple_open,
+       .read           = force_sc_support_read,
+       .write          = force_sc_support_write,
+       .llseek         = default_llseek,
+};
+
+static ssize_t sc_only_mode_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_SC_ONLY, &hdev->dev_flags) ? 'Y': 'N';
+       buf[1] = '\n';
+       buf[2] = '\0';
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static const struct file_operations sc_only_mode_fops = {
+       .open           = simple_open,
+       .read           = sc_only_mode_read,
+       .llseek         = default_llseek,
+};
+
 static int idle_timeout_set(void *data, u64 val)
 {
        struct hci_dev *hdev = data;
@@ -443,6 +492,37 @@ static int idle_timeout_get(void *data, u64 *val)
 DEFINE_SIMPLE_ATTRIBUTE(idle_timeout_fops, idle_timeout_get,
                        idle_timeout_set, "%llu\n");
 
+static int rpa_timeout_set(void *data, u64 val)
+{
+       struct hci_dev *hdev = data;
+
+       /* Require the RPA timeout to be at least 30 seconds and at most
+        * 24 hours.
+        */
+       if (val < 30 || val > (60 * 60 * 24))
+               return -EINVAL;
+
+       hci_dev_lock(hdev);
+       hdev->rpa_timeout = val;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+static int rpa_timeout_get(void *data, u64 *val)
+{
+       struct hci_dev *hdev = data;
+
+       hci_dev_lock(hdev);
+       *val = hdev->rpa_timeout;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(rpa_timeout_fops, rpa_timeout_get,
+                       rpa_timeout_set, "%llu\n");
+
 static int sniff_min_interval_set(void *data, u64 val)
 {
        struct hci_dev *hdev = data;
@@ -499,6 +579,59 @@ static int sniff_max_interval_get(void *data, u64 *val)
 DEFINE_SIMPLE_ATTRIBUTE(sniff_max_interval_fops, sniff_max_interval_get,
                        sniff_max_interval_set, "%llu\n");
 
+static int identity_show(struct seq_file *f, void *p)
+{
+       struct hci_dev *hdev = f->private;
+       bdaddr_t addr;
+       u8 addr_type;
+
+       hci_dev_lock(hdev);
+
+       hci_copy_identity_address(hdev, &addr, &addr_type);
+
+       seq_printf(f, "%pMR (type %u) %*phN %pMR\n", &addr, addr_type,
+                  16, hdev->irk, &hdev->rpa);
+
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+static int identity_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, identity_show, inode->i_private);
+}
+
+static const struct file_operations identity_fops = {
+       .open           = identity_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int random_address_show(struct seq_file *f, void *p)
+{
+       struct hci_dev *hdev = f->private;
+
+       hci_dev_lock(hdev);
+       seq_printf(f, "%pMR\n", &hdev->random_addr);
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+static int random_address_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, random_address_show, inode->i_private);
+}
+
+static const struct file_operations random_address_fops = {
+       .open           = random_address_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int static_address_show(struct seq_file *f, void *p)
 {
        struct hci_dev *hdev = f->private;
@@ -522,33 +655,107 @@ static const struct file_operations static_address_fops = {
        .release        = single_release,
 };
 
-static int own_address_type_set(void *data, u64 val)
+static ssize_t force_static_address_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
 {
-       struct hci_dev *hdev = data;
+       struct hci_dev *hdev = file->private_data;
+       char buf[3];
 
-       if (val != 0 && val != 1)
+       buf[0] = test_bit(HCI_FORCE_STATIC_ADDR, &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 force_static_address_write(struct file *file,
+                                         const char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct hci_dev *hdev = file->private_data;
+       char buf[32];
+       size_t buf_size = min(count, (sizeof(buf)-1));
+       bool enable;
+
+       if (test_bit(HCI_UP, &hdev->flags))
+               return -EBUSY;
+
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+       if (strtobool(buf, &enable))
                return -EINVAL;
 
+       if (enable == test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags))
+               return -EALREADY;
+
+       change_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags);
+
+       return count;
+}
+
+static const struct file_operations force_static_address_fops = {
+       .open           = simple_open,
+       .read           = force_static_address_read,
+       .write          = force_static_address_write,
+       .llseek         = default_llseek,
+};
+
+static int white_list_show(struct seq_file *f, void *ptr)
+{
+       struct hci_dev *hdev = f->private;
+       struct bdaddr_list *b;
+
        hci_dev_lock(hdev);
-       hdev->own_addr_type = val;
+       list_for_each_entry(b, &hdev->le_white_list, list)
+               seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
        hci_dev_unlock(hdev);
 
        return 0;
 }
 
-static int own_address_type_get(void *data, u64 *val)
+static int white_list_open(struct inode *inode, struct file *file)
 {
-       struct hci_dev *hdev = data;
+       return single_open(file, white_list_show, inode->i_private);
+}
+
+static const struct file_operations white_list_fops = {
+       .open           = white_list_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int identity_resolving_keys_show(struct seq_file *f, void *ptr)
+{
+       struct hci_dev *hdev = f->private;
+       struct list_head *p, *n;
 
        hci_dev_lock(hdev);
-       *val = hdev->own_addr_type;
+       list_for_each_safe(p, n, &hdev->identity_resolving_keys) {
+               struct smp_irk *irk = list_entry(p, struct smp_irk, list);
+               seq_printf(f, "%pMR (type %u) %*phN %pMR\n",
+                          &irk->bdaddr, irk->addr_type,
+                          16, irk->val, &irk->rpa);
+       }
        hci_dev_unlock(hdev);
 
        return 0;
 }
 
-DEFINE_SIMPLE_ATTRIBUTE(own_address_type_fops, own_address_type_get,
-                       own_address_type_set, "%llu\n");
+static int identity_resolving_keys_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, identity_resolving_keys_show,
+                          inode->i_private);
+}
+
+static const struct file_operations identity_resolving_keys_fops = {
+       .open           = identity_resolving_keys_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 static int long_term_keys_show(struct seq_file *f, void *ptr)
 {
@@ -556,12 +763,12 @@ static int long_term_keys_show(struct seq_file *f, void *ptr)
        struct list_head *p, *n;
 
        hci_dev_lock(hdev);
-       list_for_each_safe(p, n, &hdev->link_keys) {
+       list_for_each_safe(p, n, &hdev->long_term_keys) {
                struct smp_ltk *ltk = list_entry(p, struct smp_ltk, list);
-               seq_printf(f, "%pMR (type %u) %u %u %u %.4x %*phN %*phN\\n",
+               seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN\n",
                           &ltk->bdaddr, ltk->bdaddr_type, ltk->authenticated,
                           ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv),
-                          8, ltk->rand, 16, ltk->val);
+                          __le64_to_cpu(ltk->rand), 16, ltk->val);
        }
        hci_dev_unlock(hdev);
 
@@ -636,6 +843,34 @@ 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 int adv_channel_map_set(void *data, u64 val)
+{
+       struct hci_dev *hdev = data;
+
+       if (val < 0x01 || val > 0x07)
+               return -EINVAL;
+
+       hci_dev_lock(hdev);
+       hdev->le_adv_channel_map = val;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+static int adv_channel_map_get(void *data, u64 *val)
+{
+       struct hci_dev *hdev = data;
+
+       hci_dev_lock(hdev);
+       *val = hdev->le_adv_channel_map;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get,
+                       adv_channel_map_set, "%llu\n");
+
 static ssize_t lowpan_read(struct file *file, char __user *user_buf,
                           size_t count, loff_t *ppos)
 {
@@ -679,65 +914,174 @@ static const struct file_operations lowpan_debugfs_fops = {
        .llseek         = default_llseek,
 };
 
-/* ---- HCI requests ---- */
-
-static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
+static int le_auto_conn_show(struct seq_file *sf, void *ptr)
 {
-       BT_DBG("%s result 0x%2.2x", hdev->name, result);
+       struct hci_dev *hdev = sf->private;
+       struct hci_conn_params *p;
 
-       if (hdev->req_status == HCI_REQ_PEND) {
-               hdev->req_result = result;
-               hdev->req_status = HCI_REQ_DONE;
-               wake_up_interruptible(&hdev->req_wait_q);
+       hci_dev_lock(hdev);
+
+       list_for_each_entry(p, &hdev->le_conn_params, list) {
+               seq_printf(sf, "%pMR %u %u\n", &p->addr, p->addr_type,
+                          p->auto_connect);
        }
-}
 
-static void hci_req_cancel(struct hci_dev *hdev, int err)
-{
-       BT_DBG("%s err 0x%2.2x", hdev->name, err);
+       hci_dev_unlock(hdev);
 
-       if (hdev->req_status == HCI_REQ_PEND) {
-               hdev->req_result = err;
-               hdev->req_status = HCI_REQ_CANCELED;
-               wake_up_interruptible(&hdev->req_wait_q);
-       }
+       return 0;
 }
 
-static struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
-                                           u8 event)
+static int le_auto_conn_open(struct inode *inode, struct file *file)
 {
-       struct hci_ev_cmd_complete *ev;
-       struct hci_event_hdr *hdr;
-       struct sk_buff *skb;
+       return single_open(file, le_auto_conn_show, inode->i_private);
+}
 
-       hci_dev_lock(hdev);
+static ssize_t le_auto_conn_write(struct file *file, const char __user *data,
+                                 size_t count, loff_t *offset)
+{
+       struct seq_file *sf = file->private_data;
+       struct hci_dev *hdev = sf->private;
+       u8 auto_connect = 0;
+       bdaddr_t addr;
+       u8 addr_type;
+       char *buf;
+       int err = 0;
+       int n;
 
-       skb = hdev->recv_evt;
-       hdev->recv_evt = NULL;
+       /* Don't allow partial write */
+       if (*offset != 0)
+               return -EINVAL;
 
-       hci_dev_unlock(hdev);
+       if (count < 3)
+               return -EINVAL;
 
-       if (!skb)
-               return ERR_PTR(-ENODATA);
+       buf = kzalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
-       if (skb->len < sizeof(*hdr)) {
-               BT_ERR("Too short HCI event");
-               goto failed;
+       if (copy_from_user(buf, data, count)) {
+               err = -EFAULT;
+               goto done;
        }
 
-       hdr = (void *) skb->data;
-       skb_pull(skb, HCI_EVENT_HDR_SIZE);
+       if (memcmp(buf, "add", 3) == 0) {
+               n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu",
+                          &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2],
+                          &addr.b[1], &addr.b[0], &addr_type,
+                          &auto_connect);
 
-       if (event) {
-               if (hdr->evt != event)
-                       goto failed;
-               return skb;
-       }
+               if (n < 7) {
+                       err = -EINVAL;
+                       goto done;
+               }
 
-       if (hdr->evt != HCI_EV_CMD_COMPLETE) {
-               BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt);
-               goto failed;
-       }
+               hci_dev_lock(hdev);
+               err = hci_conn_params_add(hdev, &addr, addr_type, auto_connect,
+                                         hdev->le_conn_min_interval,
+                                         hdev->le_conn_max_interval);
+               hci_dev_unlock(hdev);
+
+               if (err)
+                       goto done;
+       } else if (memcmp(buf, "del", 3) == 0) {
+               n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
+                          &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2],
+                          &addr.b[1], &addr.b[0], &addr_type);
+
+               if (n < 7) {
+                       err = -EINVAL;
+                       goto done;
+               }
+
+               hci_dev_lock(hdev);
+               hci_conn_params_del(hdev, &addr, addr_type);
+               hci_dev_unlock(hdev);
+       } else if (memcmp(buf, "clr", 3) == 0) {
+               hci_dev_lock(hdev);
+               hci_conn_params_clear(hdev);
+               hci_pend_le_conns_clear(hdev);
+               hci_update_background_scan(hdev);
+               hci_dev_unlock(hdev);
+       } else {
+               err = -EINVAL;
+       }
+
+done:
+       kfree(buf);
+
+       if (err)
+               return err;
+       else
+               return count;
+}
+
+static const struct file_operations le_auto_conn_fops = {
+       .open           = le_auto_conn_open,
+       .read           = seq_read,
+       .write          = le_auto_conn_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/* ---- HCI requests ---- */
+
+static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
+{
+       BT_DBG("%s result 0x%2.2x", hdev->name, result);
+
+       if (hdev->req_status == HCI_REQ_PEND) {
+               hdev->req_result = result;
+               hdev->req_status = HCI_REQ_DONE;
+               wake_up_interruptible(&hdev->req_wait_q);
+       }
+}
+
+static void hci_req_cancel(struct hci_dev *hdev, int err)
+{
+       BT_DBG("%s err 0x%2.2x", hdev->name, err);
+
+       if (hdev->req_status == HCI_REQ_PEND) {
+               hdev->req_result = err;
+               hdev->req_status = HCI_REQ_CANCELED;
+               wake_up_interruptible(&hdev->req_wait_q);
+       }
+}
+
+static struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
+                                           u8 event)
+{
+       struct hci_ev_cmd_complete *ev;
+       struct hci_event_hdr *hdr;
+       struct sk_buff *skb;
+
+       hci_dev_lock(hdev);
+
+       skb = hdev->recv_evt;
+       hdev->recv_evt = NULL;
+
+       hci_dev_unlock(hdev);
+
+       if (!skb)
+               return ERR_PTR(-ENODATA);
+
+       if (skb->len < sizeof(*hdr)) {
+               BT_ERR("Too short HCI event");
+               goto failed;
+       }
+
+       hdr = (void *) skb->data;
+       skb_pull(skb, HCI_EVENT_HDR_SIZE);
+
+       if (event) {
+               if (hdr->evt != event)
+                       goto failed;
+               return skb;
+       }
+
+       if (hdr->evt != HCI_EV_CMD_COMPLETE) {
+               BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt);
+               goto failed;
+       }
 
        if (skb->len < sizeof(*ev)) {
                BT_ERR("Too short cmd_complete event");
@@ -1027,14 +1371,17 @@ static void le_setup(struct hci_request *req)
        /* Read LE Local Supported Features */
        hci_req_add(req, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
 
+       /* Read LE Supported States */
+       hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
+
        /* Read LE Advertising Channel TX Power */
        hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
 
        /* Read LE White List Size */
        hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
 
-       /* Read LE Supported States */
-       hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
+       /* Clear LE White List */
+       hci_req_add(req, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
 
        /* LE-only controllers have LE implicitly enabled */
        if (!lmp_bredr_capable(hdev))
@@ -1288,6 +1635,10 @@ static void hci_set_event_mask_page_2(struct hci_request *req)
                events[2] |= 0x08;      /* Truncated Page Complete */
        }
 
+       /* Enable Authenticated Payload Timeout Expired event if supported */
+       if (lmp_ping_capable(hdev))
+               events[2] |= 0x80;
+
        hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events);
 }
 
@@ -1322,21 +1673,8 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
        if (hdev->commands[5] & 0x10)
                hci_setup_link_policy(req);
 
-       if (lmp_le_capable(hdev)) {
-               if (test_bit(HCI_SETUP, &hdev->dev_flags)) {
-                       /* If the controller has a public BD_ADDR, then
-                        * by default use that one. If this is a LE only
-                        * controller without a public address, default
-                        * to the random address.
-                        */
-                       if (bacmp(&hdev->bdaddr, BDADDR_ANY))
-                               hdev->own_addr_type = ADDR_LE_DEV_PUBLIC;
-                       else
-                               hdev->own_addr_type = ADDR_LE_DEV_RANDOM;
-               }
-
+       if (lmp_le_capable(hdev))
                hci_set_le_support(req);
-       }
 
        /* Read features beyond page 1 if available */
        for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) {
@@ -1359,6 +1697,15 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)
        /* Check for Synchronization Train support */
        if (lmp_sync_train_capable(hdev))
                hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
+
+       /* Enable Secure Connections if supported and configured */
+       if ((lmp_sc_capable(hdev) ||
+            test_bit(HCI_FORCE_SC, &hdev->dev_flags)) &&
+           test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
+               u8 support = 0x01;
+               hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT,
+                           sizeof(support), &support);
+       }
 }
 
 static int __hci_init(struct hci_dev *hdev)
@@ -1417,8 +1764,6 @@ static int __hci_init(struct hci_dev *hdev)
                                    hdev, &inquiry_cache_fops);
                debugfs_create_file("link_keys", 0400, hdev->debugfs,
                                    hdev, &link_keys_fops);
-               debugfs_create_file("use_debug_keys", 0444, hdev->debugfs,
-                                   hdev, &use_debug_keys_fops);
                debugfs_create_file("dev_class", 0444, hdev->debugfs,
                                    hdev, &dev_class_fops);
                debugfs_create_file("voice_setting", 0444, hdev->debugfs,
@@ -1430,6 +1775,10 @@ static int __hci_init(struct hci_dev *hdev)
                                    hdev, &auto_accept_delay_fops);
                debugfs_create_file("ssp_debug_mode", 0644, hdev->debugfs,
                                    hdev, &ssp_debug_mode_fops);
+               debugfs_create_file("force_sc_support", 0644, hdev->debugfs,
+                                   hdev, &force_sc_support_fops);
+               debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
+                                   hdev, &sc_only_mode_fops);
        }
 
        if (lmp_sniff_capable(hdev)) {
@@ -1442,20 +1791,43 @@ static int __hci_init(struct hci_dev *hdev)
        }
 
        if (lmp_le_capable(hdev)) {
+               debugfs_create_file("identity", 0400, hdev->debugfs,
+                                   hdev, &identity_fops);
+               debugfs_create_file("rpa_timeout", 0644, hdev->debugfs,
+                                   hdev, &rpa_timeout_fops);
+               debugfs_create_file("random_address", 0444, hdev->debugfs,
+                                   hdev, &random_address_fops);
+               debugfs_create_file("static_address", 0444, hdev->debugfs,
+                                   hdev, &static_address_fops);
+
+               /* For controllers with a public address, provide a debug
+                * option to force the usage of the configured static
+                * address. By default the public address is used.
+                */
+               if (bacmp(&hdev->bdaddr, BDADDR_ANY))
+                       debugfs_create_file("force_static_address", 0644,
+                                           hdev->debugfs, hdev,
+                                           &force_static_address_fops);
+
                debugfs_create_u8("white_list_size", 0444, hdev->debugfs,
                                  &hdev->le_white_list_size);
-               debugfs_create_file("static_address", 0444, hdev->debugfs,
-                                  hdev, &static_address_fops);
-               debugfs_create_file("own_address_type", 0644, hdev->debugfs,
-                                   hdev, &own_address_type_fops);
+               debugfs_create_file("white_list", 0444, hdev->debugfs, hdev,
+                                   &white_list_fops);
+               debugfs_create_file("identity_resolving_keys", 0400,
+                                   hdev->debugfs, hdev,
+                                   &identity_resolving_keys_fops);
                debugfs_create_file("long_term_keys", 0400, hdev->debugfs,
                                    hdev, &long_term_keys_fops);
                debugfs_create_file("conn_min_interval", 0644, hdev->debugfs,
                                    hdev, &conn_min_interval_fops);
                debugfs_create_file("conn_max_interval", 0644, hdev->debugfs,
                                    hdev, &conn_max_interval_fops);
+               debugfs_create_file("adv_channel_map", 0644, hdev->debugfs,
+                                   hdev, &adv_channel_map_fops);
                debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev,
                                    &lowpan_debugfs_fops);
+               debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev,
+                                   &le_auto_conn_fops);
        }
 
        return 0;
@@ -1548,6 +1920,8 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state)
 
        switch (state) {
        case DISCOVERY_STOPPED:
+               hci_update_background_scan(hdev);
+
                if (hdev->discovery.state != DISCOVERY_STARTING)
                        mgmt_discovering(hdev, 0);
                break;
@@ -1876,10 +2250,15 @@ static int hci_dev_do_open(struct hci_dev *hdev)
                 * be able to determine if there is a public address
                 * or not.
                 *
+                * In case of user channel usage, it is not important
+                * if a public address or static random address is
+                * available.
+                *
                 * This check is only valid for BR/EDR controllers
                 * since AMP controllers do not have an address.
                 */
-               if (hdev->dev_type == HCI_BREDR &&
+               if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) &&
+                   hdev->dev_type == HCI_BREDR &&
                    !bacmp(&hdev->bdaddr, BDADDR_ANY) &&
                    !bacmp(&hdev->static_addr, BDADDR_ANY)) {
                        ret = -EADDRNOTAVAIL;
@@ -1916,6 +2295,7 @@ static int hci_dev_do_open(struct hci_dev *hdev)
 
        if (!ret) {
                hci_dev_hold(hdev);
+               set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
                if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
@@ -2014,9 +2394,13 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 
        cancel_delayed_work_sync(&hdev->le_scan_disable);
 
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               cancel_delayed_work_sync(&hdev->rpa_expired);
+
        hci_dev_lock(hdev);
        hci_inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
+       hci_pend_le_conns_clear(hdev);
        hci_dev_unlock(hdev);
 
        hci_notify(hdev, HCI_DEV_DOWN);
@@ -2074,6 +2458,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 
        memset(hdev->eir, 0, sizeof(hdev->eir));
        memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
+       bacpy(&hdev->random_addr, BDADDR_ANY);
 
        hci_req_unlock(hdev);
 
@@ -2437,7 +2822,7 @@ static void hci_discov_off(struct work_struct *work)
        mgmt_discoverable_timeout(hdev);
 }
 
-int hci_uuids_clear(struct hci_dev *hdev)
+void hci_uuids_clear(struct hci_dev *hdev)
 {
        struct bt_uuid *uuid, *tmp;
 
@@ -2445,11 +2830,9 @@ int hci_uuids_clear(struct hci_dev *hdev)
                list_del(&uuid->list);
                kfree(uuid);
        }
-
-       return 0;
 }
 
-int hci_link_keys_clear(struct hci_dev *hdev)
+void hci_link_keys_clear(struct hci_dev *hdev)
 {
        struct list_head *p, *n;
 
@@ -2461,11 +2844,9 @@ int hci_link_keys_clear(struct hci_dev *hdev)
                list_del(p);
                kfree(key);
        }
-
-       return 0;
 }
 
-int hci_smp_ltks_clear(struct hci_dev *hdev)
+void hci_smp_ltks_clear(struct hci_dev *hdev)
 {
        struct smp_ltk *k, *tmp;
 
@@ -2473,8 +2854,16 @@ int hci_smp_ltks_clear(struct hci_dev *hdev)
                list_del(&k->list);
                kfree(k);
        }
+}
 
-       return 0;
+void hci_smp_irks_clear(struct hci_dev *hdev)
+{
+       struct smp_irk *k, *tmp;
+
+       list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) {
+               list_del(&k->list);
+               kfree(k);
+       }
 }
 
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
@@ -2524,13 +2913,24 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
        return false;
 }
 
-struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
+static bool ltk_type_master(u8 type)
+{
+       if (type == HCI_SMP_STK || type == HCI_SMP_LTK)
+               return true;
+
+       return false;
+}
+
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
+                            bool master)
 {
        struct smp_ltk *k;
 
        list_for_each_entry(k, &hdev->long_term_keys, list) {
-               if (k->ediv != ediv ||
-                   memcmp(rand, k->rand, sizeof(k->rand)))
+               if (k->ediv != ediv || k->rand != rand)
+                       continue;
+
+               if (ltk_type_master(k->type) != master)
                        continue;
 
                return k;
@@ -2540,18 +2940,56 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
 }
 
 struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                    u8 addr_type)
+                                    u8 addr_type, bool master)
 {
        struct smp_ltk *k;
 
        list_for_each_entry(k, &hdev->long_term_keys, list)
                if (addr_type == k->bdaddr_type &&
-                   bacmp(bdaddr, &k->bdaddr) == 0)
+                   bacmp(bdaddr, &k->bdaddr) == 0 &&
+                   ltk_type_master(k->type) == master)
                        return k;
 
        return NULL;
 }
 
+struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
+{
+       struct smp_irk *irk;
+
+       list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
+               if (!bacmp(&irk->rpa, rpa))
+                       return irk;
+       }
+
+       list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
+               if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) {
+                       bacpy(&irk->rpa, rpa);
+                       return irk;
+               }
+       }
+
+       return NULL;
+}
+
+struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                    u8 addr_type)
+{
+       struct smp_irk *irk;
+
+       /* Identity Address must be public or static random */
+       if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0)
+               return NULL;
+
+       list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
+               if (addr_type == irk->addr_type &&
+                   bacmp(bdaddr, &irk->bdaddr) == 0)
+                       return irk;
+       }
+
+       return NULL;
+}
+
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                     bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
 {
@@ -2565,7 +3003,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                key = old_key;
        } else {
                old_key_type = conn ? conn->key_type : 0xff;
-               key = kzalloc(sizeof(*key), GFP_ATOMIC);
+               key = kzalloc(sizeof(*key), GFP_KERNEL);
                if (!key)
                        return -ENOMEM;
                list_add(&key->list, &hdev->link_keys);
@@ -2605,222 +3043,537 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
        return 0;
 }
 
-int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
-               int new_key, u8 authenticated, u8 tk[16], u8 enc_size, __le16
-               ediv, u8 rand[8])
+struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                           u8 addr_type, u8 type, u8 authenticated,
+                           u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand)
 {
        struct smp_ltk *key, *old_key;
+       bool master = ltk_type_master(type);
 
-       if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK))
-               return 0;
-
-       old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type);
+       old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master);
        if (old_key)
                key = old_key;
        else {
-               key = kzalloc(sizeof(*key), GFP_ATOMIC);
+               key = kzalloc(sizeof(*key), GFP_KERNEL);
                if (!key)
-                       return -ENOMEM;
+                       return NULL;
                list_add(&key->list, &hdev->long_term_keys);
        }
 
-       bacpy(&key->bdaddr, bdaddr);
-       key->bdaddr_type = addr_type;
-       memcpy(key->val, tk, sizeof(key->val));
-       key->authenticated = authenticated;
-       key->ediv = ediv;
-       key->enc_size = enc_size;
-       key->type = type;
-       memcpy(key->rand, rand, sizeof(key->rand));
+       bacpy(&key->bdaddr, bdaddr);
+       key->bdaddr_type = addr_type;
+       memcpy(key->val, tk, sizeof(key->val));
+       key->authenticated = authenticated;
+       key->ediv = ediv;
+       key->rand = rand;
+       key->enc_size = enc_size;
+       key->type = type;
+
+       return key;
+}
+
+struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                           u8 addr_type, u8 val[16], bdaddr_t *rpa)
+{
+       struct smp_irk *irk;
+
+       irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type);
+       if (!irk) {
+               irk = kzalloc(sizeof(*irk), GFP_KERNEL);
+               if (!irk)
+                       return NULL;
+
+               bacpy(&irk->bdaddr, bdaddr);
+               irk->addr_type = addr_type;
+
+               list_add(&irk->list, &hdev->identity_resolving_keys);
+       }
+
+       memcpy(irk->val, val, 16);
+       bacpy(&irk->rpa, rpa);
+
+       return irk;
+}
+
+int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+       struct link_key *key;
+
+       key = hci_find_link_key(hdev, bdaddr);
+       if (!key)
+               return -ENOENT;
+
+       BT_DBG("%s removing %pMR", hdev->name, bdaddr);
+
+       list_del(&key->list);
+       kfree(key);
+
+       return 0;
+}
+
+int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)
+{
+       struct smp_ltk *k, *tmp;
+       int removed = 0;
+
+       list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
+               if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type)
+                       continue;
+
+               BT_DBG("%s removing %pMR", hdev->name, bdaddr);
+
+               list_del(&k->list);
+               kfree(k);
+               removed++;
+       }
+
+       return removed ? 0 : -ENOENT;
+}
+
+void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type)
+{
+       struct smp_irk *k, *tmp;
+
+       list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) {
+               if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type)
+                       continue;
+
+               BT_DBG("%s removing %pMR", hdev->name, bdaddr);
+
+               list_del(&k->list);
+               kfree(k);
+       }
+}
+
+/* HCI command timer function */
+static void hci_cmd_timeout(unsigned long arg)
+{
+       struct hci_dev *hdev = (void *) arg;
+
+       if (hdev->sent_cmd) {
+               struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
+               u16 opcode = __le16_to_cpu(sent->opcode);
+
+               BT_ERR("%s command 0x%4.4x tx timeout", hdev->name, opcode);
+       } else {
+               BT_ERR("%s command tx timeout", hdev->name);
+       }
+
+       atomic_set(&hdev->cmd_cnt, 1);
+       queue_work(hdev->workqueue, &hdev->cmd_work);
+}
+
+struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
+                                         bdaddr_t *bdaddr)
+{
+       struct oob_data *data;
+
+       list_for_each_entry(data, &hdev->remote_oob_data, list)
+               if (bacmp(bdaddr, &data->bdaddr) == 0)
+                       return data;
+
+       return NULL;
+}
+
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+       struct oob_data *data;
+
+       data = hci_find_remote_oob_data(hdev, bdaddr);
+       if (!data)
+               return -ENOENT;
+
+       BT_DBG("%s removing %pMR", hdev->name, bdaddr);
+
+       list_del(&data->list);
+       kfree(data);
+
+       return 0;
+}
+
+void hci_remote_oob_data_clear(struct hci_dev *hdev)
+{
+       struct oob_data *data, *n;
+
+       list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) {
+               list_del(&data->list);
+               kfree(data);
+       }
+}
+
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                           u8 *hash, u8 *randomizer)
+{
+       struct oob_data *data;
+
+       data = hci_find_remote_oob_data(hdev, bdaddr);
+       if (!data) {
+               data = kmalloc(sizeof(*data), GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+
+               bacpy(&data->bdaddr, bdaddr);
+               list_add(&data->list, &hdev->remote_oob_data);
+       }
+
+       memcpy(data->hash192, hash, sizeof(data->hash192));
+       memcpy(data->randomizer192, randomizer, sizeof(data->randomizer192));
+
+       memset(data->hash256, 0, sizeof(data->hash256));
+       memset(data->randomizer256, 0, sizeof(data->randomizer256));
+
+       BT_DBG("%s for %pMR", hdev->name, bdaddr);
+
+       return 0;
+}
+
+int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                               u8 *hash192, u8 *randomizer192,
+                               u8 *hash256, u8 *randomizer256)
+{
+       struct oob_data *data;
+
+       data = hci_find_remote_oob_data(hdev, bdaddr);
+       if (!data) {
+               data = kmalloc(sizeof(*data), GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+
+               bacpy(&data->bdaddr, bdaddr);
+               list_add(&data->list, &hdev->remote_oob_data);
+       }
+
+       memcpy(data->hash192, hash192, sizeof(data->hash192));
+       memcpy(data->randomizer192, randomizer192, sizeof(data->randomizer192));
+
+       memcpy(data->hash256, hash256, sizeof(data->hash256));
+       memcpy(data->randomizer256, randomizer256, sizeof(data->randomizer256));
+
+       BT_DBG("%s for %pMR", hdev->name, bdaddr);
+
+       return 0;
+}
+
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
+                                        bdaddr_t *bdaddr, u8 type)
+{
+       struct bdaddr_list *b;
+
+       list_for_each_entry(b, &hdev->blacklist, list) {
+               if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type)
+                       return b;
+       }
+
+       return NULL;
+}
+
+static void hci_blacklist_clear(struct hci_dev *hdev)
+{
+       struct list_head *p, *n;
+
+       list_for_each_safe(p, n, &hdev->blacklist) {
+               struct bdaddr_list *b = list_entry(p, struct bdaddr_list, list);
+
+               list_del(p);
+               kfree(b);
+       }
+}
+
+int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
+{
+       struct bdaddr_list *entry;
+
+       if (!bacmp(bdaddr, BDADDR_ANY))
+               return -EBADF;
+
+       if (hci_blacklist_lookup(hdev, bdaddr, type))
+               return -EEXIST;
+
+       entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       bacpy(&entry->bdaddr, bdaddr);
+       entry->bdaddr_type = type;
+
+       list_add(&entry->list, &hdev->blacklist);
+
+       return mgmt_device_blocked(hdev, bdaddr, type);
+}
+
+int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
+{
+       struct bdaddr_list *entry;
+
+       if (!bacmp(bdaddr, BDADDR_ANY)) {
+               hci_blacklist_clear(hdev);
+               return 0;
+       }
+
+       entry = hci_blacklist_lookup(hdev, bdaddr, type);
+       if (!entry)
+               return -ENOENT;
+
+       list_del(&entry->list);
+       kfree(entry);
+
+       return mgmt_device_unblocked(hdev, bdaddr, type);
+}
+
+struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev,
+                                         bdaddr_t *bdaddr, u8 type)
+{
+       struct bdaddr_list *b;
+
+       list_for_each_entry(b, &hdev->le_white_list, list) {
+               if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type)
+                       return b;
+       }
+
+       return NULL;
+}
+
+void hci_white_list_clear(struct hci_dev *hdev)
+{
+       struct list_head *p, *n;
+
+       list_for_each_safe(p, n, &hdev->le_white_list) {
+               struct bdaddr_list *b = list_entry(p, struct bdaddr_list, list);
+
+               list_del(p);
+               kfree(b);
+       }
+}
+
+int hci_white_list_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
+{
+       struct bdaddr_list *entry;
+
+       if (!bacmp(bdaddr, BDADDR_ANY))
+               return -EBADF;
 
-       if (!new_key)
-               return 0;
+       entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       bacpy(&entry->bdaddr, bdaddr);
+       entry->bdaddr_type = type;
 
-       if (type & HCI_SMP_LTK)
-               mgmt_new_ltk(hdev, key, 1);
+       list_add(&entry->list, &hdev->le_white_list);
 
        return 0;
 }
 
-int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
-       struct link_key *key;
+       struct bdaddr_list *entry;
 
-       key = hci_find_link_key(hdev, bdaddr);
-       if (!key)
-               return -ENOENT;
+       if (!bacmp(bdaddr, BDADDR_ANY))
+               return -EBADF;
 
-       BT_DBG("%s removing %pMR", hdev->name, bdaddr);
+       entry = hci_white_list_lookup(hdev, bdaddr, type);
+       if (!entry)
+               return -ENOENT;
 
-       list_del(&key->list);
-       kfree(key);
+       list_del(&entry->list);
+       kfree(entry);
 
        return 0;
 }
 
-int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
+/* This function requires the caller holds hdev->lock */
+struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
+                                              bdaddr_t *addr, u8 addr_type)
 {
-       struct smp_ltk *k, *tmp;
-
-       list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
-               if (bacmp(bdaddr, &k->bdaddr))
-                       continue;
-
-               BT_DBG("%s removing %pMR", hdev->name, bdaddr);
+       struct hci_conn_params *params;
 
-               list_del(&k->list);
-               kfree(k);
+       list_for_each_entry(params, &hdev->le_conn_params, list) {
+               if (bacmp(&params->addr, addr) == 0 &&
+                   params->addr_type == addr_type) {
+                       return params;
+               }
        }
 
-       return 0;
+       return NULL;
 }
 
-/* HCI command timer function */
-static void hci_cmd_timeout(unsigned long arg)
+static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
 {
-       struct hci_dev *hdev = (void *) arg;
+       struct hci_conn *conn;
 
-       if (hdev->sent_cmd) {
-               struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
-               u16 opcode = __le16_to_cpu(sent->opcode);
+       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
+       if (!conn)
+               return false;
 
-               BT_ERR("%s command 0x%4.4x tx timeout", hdev->name, opcode);
-       } else {
-               BT_ERR("%s command tx timeout", hdev->name);
-       }
+       if (conn->dst_type != type)
+               return false;
 
-       atomic_set(&hdev->cmd_cnt, 1);
-       queue_work(hdev->workqueue, &hdev->cmd_work);
+       if (conn->state != BT_CONNECTED)
+               return false;
+
+       return true;
 }
 
-struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
-                                         bdaddr_t *bdaddr)
+static bool is_identity_address(bdaddr_t *addr, u8 addr_type)
 {
-       struct oob_data *data;
+       if (addr_type == ADDR_LE_DEV_PUBLIC)
+               return true;
 
-       list_for_each_entry(data, &hdev->remote_oob_data, list)
-               if (bacmp(bdaddr, &data->bdaddr) == 0)
-                       return data;
+       /* Check for Random Static address type */
+       if ((addr->b[5] & 0xc0) == 0xc0)
+               return true;
 
-       return NULL;
+       return false;
 }
 
-int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
+/* This function requires the caller holds hdev->lock */
+int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
+                       u8 auto_connect, u16 conn_min_interval,
+                       u16 conn_max_interval)
 {
-       struct oob_data *data;
+       struct hci_conn_params *params;
 
-       data = hci_find_remote_oob_data(hdev, bdaddr);
-       if (!data)
-               return -ENOENT;
+       if (!is_identity_address(addr, addr_type))
+               return -EINVAL;
 
-       BT_DBG("%s removing %pMR", hdev->name, bdaddr);
+       params = hci_conn_params_lookup(hdev, addr, addr_type);
+       if (params)
+               goto update;
 
-       list_del(&data->list);
-       kfree(data);
+       params = kzalloc(sizeof(*params), GFP_KERNEL);
+       if (!params) {
+               BT_ERR("Out of memory");
+               return -ENOMEM;
+       }
 
-       return 0;
-}
+       bacpy(&params->addr, addr);
+       params->addr_type = addr_type;
 
-int hci_remote_oob_data_clear(struct hci_dev *hdev)
-{
-       struct oob_data *data, *n;
+       list_add(&params->list, &hdev->le_conn_params);
 
-       list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) {
-               list_del(&data->list);
-               kfree(data);
+update:
+       params->conn_min_interval = conn_min_interval;
+       params->conn_max_interval = conn_max_interval;
+       params->auto_connect = auto_connect;
+
+       switch (auto_connect) {
+       case HCI_AUTO_CONN_DISABLED:
+       case HCI_AUTO_CONN_LINK_LOSS:
+               hci_pend_le_conn_del(hdev, addr, addr_type);
+               break;
+       case HCI_AUTO_CONN_ALWAYS:
+               if (!is_connected(hdev, addr, addr_type))
+                       hci_pend_le_conn_add(hdev, addr, addr_type);
+               break;
        }
 
+       BT_DBG("addr %pMR (type %u) auto_connect %u conn_min_interval 0x%.4x "
+              "conn_max_interval 0x%.4x", addr, addr_type, auto_connect,
+              conn_min_interval, conn_max_interval);
+
        return 0;
 }
 
-int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
-                           u8 *randomizer)
+/* This function requires the caller holds hdev->lock */
+void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
 {
-       struct oob_data *data;
-
-       data = hci_find_remote_oob_data(hdev, bdaddr);
-
-       if (!data) {
-               data = kmalloc(sizeof(*data), GFP_ATOMIC);
-               if (!data)
-                       return -ENOMEM;
+       struct hci_conn_params *params;
 
-               bacpy(&data->bdaddr, bdaddr);
-               list_add(&data->list, &hdev->remote_oob_data);
-       }
+       params = hci_conn_params_lookup(hdev, addr, addr_type);
+       if (!params)
+               return;
 
-       memcpy(data->hash, hash, sizeof(data->hash));
-       memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
+       hci_pend_le_conn_del(hdev, addr, addr_type);
 
-       BT_DBG("%s for %pMR", hdev->name, bdaddr);
+       list_del(&params->list);
+       kfree(params);
 
-       return 0;
+       BT_DBG("addr %pMR (type %u)", addr, addr_type);
 }
 
-struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
-                                        bdaddr_t *bdaddr, u8 type)
+/* This function requires the caller holds hdev->lock */
+void hci_conn_params_clear(struct hci_dev *hdev)
 {
-       struct bdaddr_list *b;
+       struct hci_conn_params *params, *tmp;
 
-       list_for_each_entry(b, &hdev->blacklist, list) {
-               if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type)
-                       return b;
+       list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) {
+               list_del(&params->list);
+               kfree(params);
        }
 
-       return NULL;
+       BT_DBG("All LE connection parameters were removed");
 }
 
-int hci_blacklist_clear(struct hci_dev *hdev)
+/* This function requires the caller holds hdev->lock */
+struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev,
+                                           bdaddr_t *addr, u8 addr_type)
 {
-       struct list_head *p, *n;
-
-       list_for_each_safe(p, n, &hdev->blacklist) {
-               struct bdaddr_list *b = list_entry(p, struct bdaddr_list, list);
+       struct bdaddr_list *entry;
 
-               list_del(p);
-               kfree(b);
+       list_for_each_entry(entry, &hdev->pend_le_conns, list) {
+               if (bacmp(&entry->bdaddr, addr) == 0 &&
+                   entry->bdaddr_type == addr_type)
+                       return entry;
        }
 
-       return 0;
+       return NULL;
 }
 
-int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
+/* This function requires the caller holds hdev->lock */
+void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
 {
        struct bdaddr_list *entry;
 
-       if (!bacmp(bdaddr, BDADDR_ANY))
-               return -EBADF;
+       entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
+       if (entry)
+               goto done;
 
-       if (hci_blacklist_lookup(hdev, bdaddr, type))
-               return -EEXIST;
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry) {
+               BT_ERR("Out of memory");
+               return;
+       }
 
-       entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
-       if (!entry)
-               return -ENOMEM;
+       bacpy(&entry->bdaddr, addr);
+       entry->bdaddr_type = addr_type;
 
-       bacpy(&entry->bdaddr, bdaddr);
-       entry->bdaddr_type = type;
+       list_add(&entry->list, &hdev->pend_le_conns);
 
-       list_add(&entry->list, &hdev->blacklist);
+       BT_DBG("addr %pMR (type %u)", addr, addr_type);
 
-       return mgmt_device_blocked(hdev, bdaddr, type);
+done:
+       hci_update_background_scan(hdev);
 }
 
-int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
+/* This function requires the caller holds hdev->lock */
+void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
 {
        struct bdaddr_list *entry;
 
-       if (!bacmp(bdaddr, BDADDR_ANY))
-               return hci_blacklist_clear(hdev);
-
-       entry = hci_blacklist_lookup(hdev, bdaddr, type);
+       entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
        if (!entry)
-               return -ENOENT;
+               goto done;
 
        list_del(&entry->list);
        kfree(entry);
 
-       return mgmt_device_unblocked(hdev, bdaddr, type);
+       BT_DBG("addr %pMR (type %u)", addr, addr_type);
+
+done:
+       hci_update_background_scan(hdev);
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_pend_le_conns_clear(struct hci_dev *hdev)
+{
+       struct bdaddr_list *entry, *tmp;
+
+       list_for_each_entry_safe(entry, tmp, &hdev->pend_le_conns, list) {
+               list_del(&entry->list);
+               kfree(entry);
+       }
+
+       BT_DBG("All LE pending connections cleared");
 }
 
 static void inquiry_complete(struct hci_dev *hdev, u8 status)
@@ -2882,7 +3635,6 @@ static void le_scan_disable_work(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
                                            le_scan_disable.work);
-       struct hci_cp_le_set_scan_enable cp;
        struct hci_request req;
        int err;
 
@@ -2890,15 +3642,128 @@ static void le_scan_disable_work(struct work_struct *work)
 
        hci_req_init(&req, hdev);
 
-       memset(&cp, 0, sizeof(cp));
-       cp.enable = LE_SCAN_DISABLE;
-       hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+       hci_req_add_le_scan_disable(&req);
 
        err = hci_req_run(&req, le_scan_disable_work_complete);
        if (err)
                BT_ERR("Disable LE scanning request failed: err %d", err);
 }
 
+static void set_random_addr(struct hci_request *req, bdaddr_t *rpa)
+{
+       struct hci_dev *hdev = req->hdev;
+
+       /* If we're advertising or initiating an LE connection we can't
+        * go ahead and change the random address at this time. This is
+        * because the eventual initiator address used for the
+        * subsequently created connection will be undefined (some
+        * controllers use the new address and others the one we had
+        * when the operation started).
+        *
+        * In this kind of scenario skip the update and let the random
+        * address be updated at the next cycle.
+        */
+       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) ||
+           hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) {
+               BT_DBG("Deferring random address update");
+               return;
+       }
+
+       hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, rpa);
+}
+
+int hci_update_random_address(struct hci_request *req, bool require_privacy,
+                             u8 *own_addr_type)
+{
+       struct hci_dev *hdev = req->hdev;
+       int err;
+
+       /* If privacy is enabled use a resolvable private address. If
+        * current RPA has expired or there is something else than
+        * the current RPA in use, then generate a new one.
+        */
+       if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) {
+               int to;
+
+               *own_addr_type = ADDR_LE_DEV_RANDOM;
+
+               if (!test_and_clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags) &&
+                   !bacmp(&hdev->random_addr, &hdev->rpa))
+                       return 0;
+
+               err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa);
+               if (err < 0) {
+                       BT_ERR("%s failed to generate new RPA", hdev->name);
+                       return err;
+               }
+
+               set_random_addr(req, &hdev->rpa);
+
+               to = msecs_to_jiffies(hdev->rpa_timeout * 1000);
+               queue_delayed_work(hdev->workqueue, &hdev->rpa_expired, to);
+
+               return 0;
+       }
+
+       /* In case of required privacy without resolvable private address,
+        * use an unresolvable private address. This is useful for active
+        * scanning and non-connectable advertising.
+        */
+       if (require_privacy) {
+               bdaddr_t urpa;
+
+               get_random_bytes(&urpa, 6);
+               urpa.b[5] &= 0x3f;      /* Clear two most significant bits */
+
+               *own_addr_type = ADDR_LE_DEV_RANDOM;
+               set_random_addr(req, &urpa);
+               return 0;
+       }
+
+       /* If forcing static address is in use or there is no public
+        * address use the static address as random address (but skip
+        * the HCI command if the current random address is already the
+        * static one.
+        */
+       if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) ||
+           !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
+               *own_addr_type = ADDR_LE_DEV_RANDOM;
+               if (bacmp(&hdev->static_addr, &hdev->random_addr))
+                       hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
+                                   &hdev->static_addr);
+               return 0;
+       }
+
+       /* Neither privacy nor static address is being used so use a
+        * public address.
+        */
+       *own_addr_type = ADDR_LE_DEV_PUBLIC;
+
+       return 0;
+}
+
+/* Copy the Identity Address of the controller.
+ *
+ * If the controller has a public BD_ADDR, then by default use that one.
+ * If this is a LE only controller without a public address, default to
+ * the static random address.
+ *
+ * For debugging purposes it is possible to force controllers with a
+ * public address to use the static random address instead.
+ */
+void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                              u8 *bdaddr_type)
+{
+       if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) ||
+           !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
+               bacpy(bdaddr, &hdev->static_addr);
+               *bdaddr_type = ADDR_LE_DEV_RANDOM;
+       } else {
+               bacpy(bdaddr, &hdev->bdaddr);
+               *bdaddr_type = ADDR_LE_DEV_PUBLIC;
+       }
+}
+
 /* Alloc HCI device */
 struct hci_dev *hci_alloc_dev(void)
 {
@@ -2919,11 +3784,14 @@ struct hci_dev *hci_alloc_dev(void)
        hdev->sniff_max_interval = 800;
        hdev->sniff_min_interval = 80;
 
+       hdev->le_adv_channel_map = 0x07;
        hdev->le_scan_interval = 0x0060;
        hdev->le_scan_window = 0x0030;
        hdev->le_conn_min_interval = 0x0028;
        hdev->le_conn_max_interval = 0x0038;
 
+       hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT;
+
        mutex_init(&hdev->lock);
        mutex_init(&hdev->req_lock);
 
@@ -2932,7 +3800,11 @@ struct hci_dev *hci_alloc_dev(void)
        INIT_LIST_HEAD(&hdev->uuids);
        INIT_LIST_HEAD(&hdev->link_keys);
        INIT_LIST_HEAD(&hdev->long_term_keys);
+       INIT_LIST_HEAD(&hdev->identity_resolving_keys);
        INIT_LIST_HEAD(&hdev->remote_oob_data);
+       INIT_LIST_HEAD(&hdev->le_white_list);
+       INIT_LIST_HEAD(&hdev->le_conn_params);
+       INIT_LIST_HEAD(&hdev->pend_le_conns);
        INIT_LIST_HEAD(&hdev->conn_hash.list);
 
        INIT_WORK(&hdev->rx_work, hci_rx_work);
@@ -3017,9 +3889,18 @@ int hci_register_dev(struct hci_dev *hdev)
 
        dev_set_name(&hdev->dev, "%s", hdev->name);
 
+       hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0,
+                                              CRYPTO_ALG_ASYNC);
+       if (IS_ERR(hdev->tfm_aes)) {
+               BT_ERR("Unable to create crypto context");
+               error = PTR_ERR(hdev->tfm_aes);
+               hdev->tfm_aes = NULL;
+               goto err_wqueue;
+       }
+
        error = device_add(&hdev->dev);
        if (error < 0)
-               goto err_wqueue;
+               goto err_tfm;
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
                                    RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
@@ -3055,6 +3936,8 @@ int hci_register_dev(struct hci_dev *hdev)
 
        return id;
 
+err_tfm:
+       crypto_free_blkcipher(hdev->tfm_aes);
 err_wqueue:
        destroy_workqueue(hdev->workqueue);
        destroy_workqueue(hdev->req_workqueue);
@@ -3105,6 +3988,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
                rfkill_destroy(hdev->rfkill);
        }
 
+       if (hdev->tfm_aes)
+               crypto_free_blkcipher(hdev->tfm_aes);
+
        device_del(&hdev->dev);
 
        debugfs_remove_recursive(hdev->debugfs);
@@ -3117,7 +4003,11 @@ void hci_unregister_dev(struct hci_dev *hdev)
        hci_uuids_clear(hdev);
        hci_link_keys_clear(hdev);
        hci_smp_ltks_clear(hdev);
+       hci_smp_irks_clear(hdev);
        hci_remote_oob_data_clear(hdev);
+       hci_white_list_clear(hdev);
+       hci_conn_params_clear(hdev);
+       hci_pend_le_conns_clear(hdev);
        hci_dev_unlock(hdev);
 
        hci_dev_put(hdev);
@@ -4345,3 +5235,102 @@ static void hci_cmd_work(struct work_struct *work)
                }
        }
 }
+
+void hci_req_add_le_scan_disable(struct hci_request *req)
+{
+       struct hci_cp_le_set_scan_enable cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.enable = LE_SCAN_DISABLE;
+       hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+}
+
+void hci_req_add_le_passive_scan(struct hci_request *req)
+{
+       struct hci_cp_le_set_scan_param param_cp;
+       struct hci_cp_le_set_scan_enable enable_cp;
+       struct hci_dev *hdev = req->hdev;
+       u8 own_addr_type;
+
+       /* Set require_privacy to true to avoid identification from
+        * unknown peer devices. Since this is passive scanning, no
+        * SCAN_REQ using the local identity should be sent. Mandating
+        * privacy is just an extra precaution.
+        */
+       if (hci_update_random_address(req, true, &own_addr_type))
+               return;
+
+       memset(&param_cp, 0, sizeof(param_cp));
+       param_cp.type = LE_SCAN_PASSIVE;
+       param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
+       param_cp.window = cpu_to_le16(hdev->le_scan_window);
+       param_cp.own_address_type = own_addr_type;
+       hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
+                   &param_cp);
+
+       memset(&enable_cp, 0, sizeof(enable_cp));
+       enable_cp.enable = LE_SCAN_ENABLE;
+       enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+       hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+                   &enable_cp);
+}
+
+static void update_background_scan_complete(struct hci_dev *hdev, u8 status)
+{
+       if (status)
+               BT_DBG("HCI request failed to update background scanning: "
+                      "status 0x%2.2x", status);
+}
+
+/* This function controls the background scanning based on hdev->pend_le_conns
+ * list. If there are pending LE connection we start the background scanning,
+ * otherwise we stop it.
+ *
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_update_background_scan(struct hci_dev *hdev)
+{
+       struct hci_request req;
+       struct hci_conn *conn;
+       int err;
+
+       hci_req_init(&req, hdev);
+
+       if (list_empty(&hdev->pend_le_conns)) {
+               /* If there is no pending LE connections, we should stop
+                * the background scanning.
+                */
+
+               /* If controller is not scanning we are done. */
+               if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+                       return;
+
+               hci_req_add_le_scan_disable(&req);
+
+               BT_DBG("%s stopping background scanning", hdev->name);
+       } else {
+               /* If there is at least one pending LE connection, we should
+                * keep the background scan running.
+                */
+
+               /* If controller is already scanning we are done. */
+               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+                       return;
+
+               /* If controller is connecting, we should not start scanning
+                * since some controllers are not able to scan and connect at
+                * the same time.
+                */
+               conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+               if (conn)
+                       return;
+
+               hci_req_add_le_passive_scan(&req);
+
+               BT_DBG("%s starting background scanning", hdev->name);
+       }
+
+       err = hci_req_run(&req, update_background_scan_complete);
+       if (err)
+               BT_ERR("Failed to run HCI request: err %d", err);
+}
index 5f812455a4504260927cb2dd5a3bdc018e0e20d4..c3b0a08f5ab4e8c3e21423a282877e44c89d850e 100644 (file)
@@ -461,6 +461,34 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
+static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       u8 status = *((u8 *) skb->data);
+       struct hci_cp_write_sc_support *sent;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SC_SUPPORT);
+       if (!sent)
+               return;
+
+       if (!status) {
+               if (sent->support)
+                       hdev->features[1][0] |= LMP_HOST_SC;
+               else
+                       hdev->features[1][0] &= ~LMP_HOST_SC;
+       }
+
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_sc_enable_complete(hdev, sent->support, status);
+       else if (!status) {
+               if (sent->support)
+                       set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
+               else
+                       clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
+       }
+}
+
 static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_rp_read_local_version *rp = (void *) skb->data;
@@ -904,16 +932,50 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
        hci_dev_unlock(hdev);
 }
 
-static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
-                                            struct sk_buff *skb)
+static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
+                                      struct sk_buff *skb)
 {
        struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
        hci_dev_lock(hdev);
-       mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
-                                               rp->randomizer, rp->status);
+       mgmt_read_local_oob_data_complete(hdev, rp->hash, rp->randomizer,
+                                         NULL, NULL, rp->status);
+       hci_dev_unlock(hdev);
+}
+
+static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev,
+                                          struct sk_buff *skb)
+{
+       struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       hci_dev_lock(hdev);
+       mgmt_read_local_oob_data_complete(hdev, rp->hash192, rp->randomizer192,
+                                         rp->hash256, rp->randomizer256,
+                                         rp->status);
+       hci_dev_unlock(hdev);
+}
+
+
+static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       bdaddr_t *sent;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR);
+       if (!sent)
+               return;
+
+       hci_dev_lock(hdev);
+
+       if (!status)
+               bacpy(&hdev->random_addr, sent);
+
        hci_dev_unlock(hdev);
 }
 
@@ -929,12 +991,8 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (!status) {
-               if (*sent)
-                       set_bit(HCI_ADVERTISING, &hdev->dev_flags);
-               else
-                       clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
-       }
+       if (!status)
+               mgmt_advertising(hdev, *sent);
 
        hci_dev_unlock(hdev);
 }
@@ -960,7 +1018,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
                break;
 
        case LE_SCAN_DISABLE:
+               /* Cancel this timer so that we don't try to disable scanning
+                * when it's already disabled.
+                */
+               cancel_delayed_work(&hdev->le_scan_disable);
+
                clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
+               /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
+                * interrupted scanning due to a connect request. Mark
+                * therefore discovery as stopped.
+                */
+               if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED,
+                                      &hdev->dev_flags))
+                       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
                break;
 
        default:
@@ -980,6 +1050,49 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
                hdev->le_white_list_size = rp->size;
 }
 
+static void hci_cc_le_clear_white_list(struct hci_dev *hdev,
+                                      struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (!status)
+               hci_white_list_clear(hdev);
+}
+
+static void hci_cc_le_add_to_white_list(struct hci_dev *hdev,
+                                       struct sk_buff *skb)
+{
+       struct hci_cp_le_add_to_white_list *sent;
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST);
+       if (!sent)
+               return;
+
+       if (!status)
+               hci_white_list_add(hdev, &sent->bdaddr, sent->bdaddr_type);
+}
+
+static void hci_cc_le_del_from_white_list(struct hci_dev *hdev,
+                                         struct sk_buff *skb)
+{
+       struct hci_cp_le_del_from_white_list *sent;
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST);
+       if (!sent)
+               return;
+
+       if (!status)
+               hci_white_list_del(hdev, &sent->bdaddr, sent->bdaddr_type);
+}
+
 static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
                                            struct sk_buff *skb)
 {
@@ -1020,6 +1133,25 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
        }
 }
 
+static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_cp_le_set_adv_param *cp;
+       u8 status = *((u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_PARAM);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+       hdev->adv_addr_type = cp->own_address_type;
+       hci_dev_unlock(hdev);
+}
+
 static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
                                          struct sk_buff *skb)
 {
@@ -1185,9 +1317,12 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
                return 0;
 
        /* Only request authentication for SSP connections or non-SSP
-        * devices with sec_level HIGH or if MITM protection is requested */
+        * devices with sec_level MEDIUM or HIGH or if MITM protection
+        * is requested.
+        */
        if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) &&
-           conn->pending_sec_level != BT_SECURITY_HIGH)
+           conn->pending_sec_level != BT_SECURITY_HIGH &&
+           conn->pending_sec_level != BT_SECURITY_MEDIUM)
                return 0;
 
        return 1;
@@ -1518,6 +1653,57 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
        amp_write_remote_assoc(hdev, cp->phy_handle);
 }
 
+static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_le_create_conn *cp;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       /* All connection failure handling is taken care of by the
+        * hci_le_conn_failed function which is triggered by the HCI
+        * request completion callbacks used for connecting.
+        */
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
+       if (!conn)
+               goto unlock;
+
+       /* Store the initiator and responder address information which
+        * is needed for SMP. These values will not change during the
+        * lifetime of the connection.
+        */
+       conn->init_addr_type = cp->own_address_type;
+       if (cp->own_address_type == ADDR_LE_DEV_RANDOM)
+               bacpy(&conn->init_addr, &hdev->random_addr);
+       else
+               bacpy(&conn->init_addr, &hdev->bdaddr);
+
+       conn->resp_addr_type = cp->peer_addr_type;
+       bacpy(&conn->resp_addr, &cp->peer_addr);
+
+       /* We don't want the connection attempt to stick around
+        * indefinitely since LE doesn't have a page timeout concept
+        * like BR/EDR. Set a timer for any connection that doesn't use
+        * the white list for connecting.
+        */
+       if (cp->filter_policy == HCI_LE_USE_PEER_ADDR)
+               queue_delayed_work(conn->hdev->workqueue,
+                                  &conn->le_conn_timeout,
+                                  HCI_LE_CONN_TIMEOUT);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
 static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -1659,7 +1845,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        } else {
                conn->state = BT_CLOSED;
                if (conn->type == ACL_LINK)
-                       mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
+                       mgmt_connect_failed(hdev, &conn->dst, conn->type,
                                            conn->dst_type, ev->status);
        }
 
@@ -1780,7 +1966,9 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_disconn_complete *ev = (void *) skb->data;
        u8 reason = hci_to_mgmt_reason(ev->reason);
+       struct hci_conn_params *params;
        struct hci_conn *conn;
+       bool mgmt_connected;
        u8 type;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
@@ -1799,13 +1987,30 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        conn->state = BT_CLOSED;
 
-       if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-               mgmt_device_disconnected(hdev, &conn->dst, conn->type,
-                                        conn->dst_type, reason);
+       mgmt_connected = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
+       mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
+                               reason, mgmt_connected);
 
        if (conn->type == ACL_LINK && conn->flush_key)
                hci_remove_link_key(hdev, &conn->dst);
 
+       params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
+       if (params) {
+               switch (params->auto_connect) {
+               case HCI_AUTO_CONN_LINK_LOSS:
+                       if (ev->reason != HCI_ERROR_CONNECTION_TIMEOUT)
+                               break;
+                       /* Fall through */
+
+               case HCI_AUTO_CONN_ALWAYS:
+                       hci_pend_le_conn_add(hdev, &conn->dst, conn->dst_type);
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
        type = conn->type;
 
        hci_proto_disconn_cfm(conn, ev->reason);
@@ -1943,35 +2148,46 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-       if (conn) {
-               if (!ev->status) {
-                       if (ev->encrypt) {
-                               /* Encryption implies authentication */
-                               conn->link_mode |= HCI_LM_AUTH;
-                               conn->link_mode |= HCI_LM_ENCRYPT;
-                               conn->sec_level = conn->pending_sec_level;
-                       } else
-                               conn->link_mode &= ~HCI_LM_ENCRYPT;
-               }
+       if (!conn)
+               goto unlock;
 
-               clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
+       if (!ev->status) {
+               if (ev->encrypt) {
+                       /* Encryption implies authentication */
+                       conn->link_mode |= HCI_LM_AUTH;
+                       conn->link_mode |= HCI_LM_ENCRYPT;
+                       conn->sec_level = conn->pending_sec_level;
 
-               if (ev->status && conn->state == BT_CONNECTED) {
-                       hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
-                       hci_conn_drop(conn);
-                       goto unlock;
+                       /* P-256 authentication key implies FIPS */
+                       if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256)
+                               conn->link_mode |= HCI_LM_FIPS;
+
+                       if ((conn->type == ACL_LINK && ev->encrypt == 0x02) ||
+                           conn->type == LE_LINK)
+                               set_bit(HCI_CONN_AES_CCM, &conn->flags);
+               } else {
+                       conn->link_mode &= ~HCI_LM_ENCRYPT;
+                       clear_bit(HCI_CONN_AES_CCM, &conn->flags);
                }
+       }
 
-               if (conn->state == BT_CONFIG) {
-                       if (!ev->status)
-                               conn->state = BT_CONNECTED;
+       clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 
-                       hci_proto_connect_cfm(conn, ev->status);
-                       hci_conn_drop(conn);
-               } else
-                       hci_encrypt_cfm(conn, ev->status, ev->encrypt);
+       if (ev->status && conn->state == BT_CONNECTED) {
+               hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
+               hci_conn_drop(conn);
+               goto unlock;
        }
 
+       if (conn->state == BT_CONFIG) {
+               if (!ev->status)
+                       conn->state = BT_CONNECTED;
+
+               hci_proto_connect_cfm(conn, ev->status);
+               hci_conn_drop(conn);
+       } else
+               hci_encrypt_cfm(conn, ev->status, ev->encrypt);
+
 unlock:
        hci_dev_unlock(hdev);
 }
@@ -2144,6 +2360,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_write_ssp_mode(hdev, skb);
                break;
 
+       case HCI_OP_WRITE_SC_SUPPORT:
+               hci_cc_write_sc_support(hdev, skb);
+               break;
+
        case HCI_OP_READ_LOCAL_VERSION:
                hci_cc_read_local_version(hdev, skb);
                break;
@@ -2213,7 +2433,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                break;
 
        case HCI_OP_READ_LOCAL_OOB_DATA:
-               hci_cc_read_local_oob_data_reply(hdev, skb);
+               hci_cc_read_local_oob_data(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_OOB_EXT_DATA:
+               hci_cc_read_local_oob_ext_data(hdev, skb);
                break;
 
        case HCI_OP_LE_READ_BUFFER_SIZE:
@@ -2244,6 +2468,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_user_passkey_neg_reply(hdev, skb);
                break;
 
+       case HCI_OP_LE_SET_RANDOM_ADDR:
+               hci_cc_le_set_random_addr(hdev, skb);
+               break;
+
        case HCI_OP_LE_SET_ADV_ENABLE:
                hci_cc_le_set_adv_enable(hdev, skb);
                break;
@@ -2256,6 +2484,18 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_le_read_white_list_size(hdev, skb);
                break;
 
+       case HCI_OP_LE_CLEAR_WHITE_LIST:
+               hci_cc_le_clear_white_list(hdev, skb);
+               break;
+
+       case HCI_OP_LE_ADD_TO_WHITE_LIST:
+               hci_cc_le_add_to_white_list(hdev, skb);
+               break;
+
+       case HCI_OP_LE_DEL_FROM_WHITE_LIST:
+               hci_cc_le_del_from_white_list(hdev, skb);
+               break;
+
        case HCI_OP_LE_READ_SUPPORTED_STATES:
                hci_cc_le_read_supported_states(hdev, skb);
                break;
@@ -2264,6 +2504,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_write_le_host_supported(hdev, skb);
                break;
 
+       case HCI_OP_LE_SET_ADV_PARAM:
+               hci_cc_set_adv_param(hdev, skb);
+               break;
+
        case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
                hci_cc_write_remote_amp_assoc(hdev, skb);
                break;
@@ -2351,6 +2595,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cs_accept_phylink(hdev, ev->status);
                break;
 
+       case HCI_OP_LE_CREATE_CONN:
+               hci_cs_le_create_conn(hdev, ev->status);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -2630,7 +2878,8 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (conn) {
-               if (key->type == HCI_LK_UNAUTH_COMBINATION &&
+               if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 ||
+                    key->type == HCI_LK_UNAUTH_COMBINATION_P256) &&
                    conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
                        BT_DBG("%s ignoring unauthenticated key", hdev->name);
                        goto not_found;
@@ -2844,6 +3093,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
                         * features do not indicate SSP support */
                        clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
                }
+
+               if (ev->features[0] & LMP_HOST_SC)
+                       set_bit(HCI_CONN_SC_ENABLED, &conn->flags);
        }
 
        if (conn->state != BT_CONFIG)
@@ -3337,20 +3589,36 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 
        data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
        if (data) {
-               struct hci_cp_remote_oob_data_reply cp;
+               if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
+                       struct hci_cp_remote_oob_ext_data_reply cp;
 
-               bacpy(&cp.bdaddr, &ev->bdaddr);
-               memcpy(cp.hash, data->hash, sizeof(cp.hash));
-               memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
+                       bacpy(&cp.bdaddr, &ev->bdaddr);
+                       memcpy(cp.hash192, data->hash192, sizeof(cp.hash192));
+                       memcpy(cp.randomizer192, data->randomizer192,
+                              sizeof(cp.randomizer192));
+                       memcpy(cp.hash256, data->hash256, sizeof(cp.hash256));
+                       memcpy(cp.randomizer256, data->randomizer256,
+                              sizeof(cp.randomizer256));
+
+                       hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_EXT_DATA_REPLY,
+                                    sizeof(cp), &cp);
+               } else {
+                       struct hci_cp_remote_oob_data_reply cp;
+
+                       bacpy(&cp.bdaddr, &ev->bdaddr);
+                       memcpy(cp.hash, data->hash192, sizeof(cp.hash));
+                       memcpy(cp.randomizer, data->randomizer192,
+                              sizeof(cp.randomizer));
 
-               hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
-                            &cp);
+                       hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY,
+                                    sizeof(cp), &cp);
+               }
        } else {
                struct hci_cp_remote_oob_data_neg_reply cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-               hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
-                            &cp);
+               hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY,
+                            sizeof(cp), &cp);
        }
 
 unlock:
@@ -3484,6 +3752,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_le_conn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
+       struct smp_irk *irk;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
 
@@ -3514,19 +3783,70 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                        conn->out = true;
                        conn->link_mode |= HCI_LM_MASTER;
                }
+
+               /* If we didn't have a hci_conn object previously
+                * but we're in master role this must be something
+                * initiated using a white list. Since white list based
+                * connections are not "first class citizens" we don't
+                * have full tracking of them. Therefore, we go ahead
+                * with a "best effort" approach of determining the
+                * initiator address based on the HCI_PRIVACY flag.
+                */
+               if (conn->out) {
+                       conn->resp_addr_type = ev->bdaddr_type;
+                       bacpy(&conn->resp_addr, &ev->bdaddr);
+                       if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) {
+                               conn->init_addr_type = ADDR_LE_DEV_RANDOM;
+                               bacpy(&conn->init_addr, &hdev->rpa);
+                       } else {
+                               hci_copy_identity_address(hdev,
+                                                         &conn->init_addr,
+                                                         &conn->init_addr_type);
+                       }
+               } else {
+                       /* Set the responder (our side) address type based on
+                        * the advertising address type.
+                        */
+                       conn->resp_addr_type = hdev->adv_addr_type;
+                       if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM)
+                               bacpy(&conn->resp_addr, &hdev->random_addr);
+                       else
+                               bacpy(&conn->resp_addr, &hdev->bdaddr);
+
+                       conn->init_addr_type = ev->bdaddr_type;
+                       bacpy(&conn->init_addr, &ev->bdaddr);
+               }
+       } else {
+               cancel_delayed_work(&conn->le_conn_timeout);
+       }
+
+       /* Ensure that the hci_conn contains the identity address type
+        * regardless of which address the connection was made with.
+        */
+       hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
+
+       /* Lookup the identity address from the stored connection
+        * address and address type.
+        *
+        * When establishing connections to an identity address, the
+        * connection procedure will store the resolvable random
+        * address first. Now if it can be converted back into the
+        * identity address, start using the identity address from
+        * now on.
+        */
+       irk = hci_get_irk(hdev, &conn->dst, conn->dst_type);
+       if (irk) {
+               bacpy(&conn->dst, &irk->bdaddr);
+               conn->dst_type = irk->addr_type;
        }
 
        if (ev->status) {
-               mgmt_connect_failed(hdev, &conn->dst, conn->type,
-                                   conn->dst_type, ev->status);
-               hci_proto_connect_cfm(conn, ev->status);
-               conn->state = BT_CLOSED;
-               hci_conn_del(conn);
+               hci_le_conn_failed(conn, ev->status);
                goto unlock;
        }
 
        if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-               mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
+               mgmt_device_connected(hdev, &conn->dst, conn->type,
                                      conn->dst_type, 0, NULL, 0, NULL);
 
        conn->sec_level = BT_SECURITY_LOW;
@@ -3540,25 +3860,73 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_proto_connect_cfm(conn, ev->status);
 
+       hci_pend_le_conn_del(hdev, &conn->dst, conn->dst_type);
+
 unlock:
        hci_dev_unlock(hdev);
 }
 
+/* This function requires the caller holds hdev->lock */
+static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
+                                 u8 addr_type)
+{
+       struct hci_conn *conn;
+       struct smp_irk *irk;
+
+       /* If this is a resolvable address, we should resolve it and then
+        * update address and address type variables.
+        */
+       irk = hci_get_irk(hdev, addr, addr_type);
+       if (irk) {
+               addr = &irk->bdaddr;
+               addr_type = irk->addr_type;
+       }
+
+       if (!hci_pend_le_conn_lookup(hdev, addr, addr_type))
+               return;
+
+       conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
+                             HCI_AT_NO_BONDING);
+       if (!IS_ERR(conn))
+               return;
+
+       switch (PTR_ERR(conn)) {
+       case -EBUSY:
+               /* If hci_connect() returns -EBUSY it means there is already
+                * an LE connection attempt going on. Since controllers don't
+                * support more than one connection attempt at the time, we
+                * don't consider this an error case.
+                */
+               break;
+       default:
+               BT_DBG("Failed to connect: err %ld", PTR_ERR(conn));
+       }
+}
+
 static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        u8 num_reports = skb->data[0];
        void *ptr = &skb->data[1];
        s8 rssi;
 
+       hci_dev_lock(hdev);
+
        while (num_reports--) {
                struct hci_ev_le_advertising_info *ev = ptr;
 
+               if (ev->evt_type == LE_ADV_IND ||
+                   ev->evt_type == LE_ADV_DIRECT_IND)
+                       check_pending_le_conn(hdev, &ev->bdaddr,
+                                             ev->bdaddr_type);
+
                rssi = ev->data[ev->length];
                mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
                                  NULL, rssi, 0, 1, ev->data, ev->length);
 
                ptr += sizeof(*ev) + ev->length + 1;
        }
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -3577,7 +3945,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
        if (conn == NULL)
                goto not_found;
 
-       ltk = hci_find_ltk(hdev, ev->ediv, ev->random);
+       ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->out);
        if (ltk == NULL)
                goto not_found;
 
index 7552f9e3089ce790040268f1ce0a067d6ef728cb..68e51a84e72ddb4f2eeba3fc76458d6a8f8a1c06 100644 (file)
@@ -716,6 +716,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
                err = hci_dev_open(hdev->id);
                if (err) {
                        clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags);
+                       mgmt_index_added(hdev);
                        hci_dev_put(hdev);
                        goto done;
                }
index 0b61250cfdf90c9e3a488c9ca3cce41ac79d6a84..555982a78a585513431722a7f65e1934dc081f86 100644 (file)
@@ -49,14 +49,7 @@ static struct attribute *bt_link_attrs[] = {
        NULL
 };
 
-static struct attribute_group bt_link_group = {
-       .attrs = bt_link_attrs,
-};
-
-static const struct attribute_group *bt_link_groups[] = {
-       &bt_link_group,
-       NULL
-};
+ATTRIBUTE_GROUPS(bt_link);
 
 static void bt_link_release(struct device *dev)
 {
@@ -182,14 +175,7 @@ static struct attribute *bt_host_attrs[] = {
        NULL
 };
 
-static struct attribute_group bt_host_group = {
-       .attrs = bt_host_attrs,
-};
-
-static const struct attribute_group *bt_host_groups[] = {
-       &bt_host_group,
-       NULL
-};
+ATTRIBUTE_GROUPS(bt_host);
 
 static void bt_host_release(struct device *dev)
 {
index b0ad2c752d738039cff8ec32c028dd109a10388b..9ed2168fa59f5243ad187bef4836ef9c9ce212d7 100644 (file)
@@ -42,6 +42,8 @@
 #include "amp.h"
 #include "6lowpan.h"
 
+#define LE_FLOWCTL_MAX_CREDITS 65535
+
 bool disable_ertm;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
@@ -330,44 +332,20 @@ static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list,
        return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR;
 }
 
-static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq)
+static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list)
 {
+       u16 seq = seq_list->head;
        u16 mask = seq_list->mask;
 
-       if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) {
-               /* In case someone tries to pop the head of an empty list */
-               return L2CAP_SEQ_LIST_CLEAR;
-       } else if (seq_list->head == seq) {
-               /* Head can be removed in constant time */
-               seq_list->head = seq_list->list[seq & mask];
-               seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR;
-
-               if (seq_list->head == L2CAP_SEQ_LIST_TAIL) {
-                       seq_list->head = L2CAP_SEQ_LIST_CLEAR;
-                       seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
-               }
-       } else {
-               /* Walk the list to find the sequence number */
-               u16 prev = seq_list->head;
-               while (seq_list->list[prev & mask] != seq) {
-                       prev = seq_list->list[prev & mask];
-                       if (prev == L2CAP_SEQ_LIST_TAIL)
-                               return L2CAP_SEQ_LIST_CLEAR;
-               }
+       seq_list->head = seq_list->list[seq & mask];
+       seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR;
 
-               /* Unlink the number from the list and clear it */
-               seq_list->list[prev & mask] = seq_list->list[seq & mask];
-               seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR;
-               if (seq_list->tail == seq)
-                       seq_list->tail = prev;
+       if (seq_list->head == L2CAP_SEQ_LIST_TAIL) {
+               seq_list->head = L2CAP_SEQ_LIST_CLEAR;
+               seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
        }
-       return seq;
-}
 
-static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list)
-{
-       /* Remove the head in constant time */
-       return l2cap_seq_list_remove(seq_list, seq_list->head);
+       return seq;
 }
 
 static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list)
@@ -506,7 +484,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
        chan->sdu_len = 0;
        chan->tx_credits = 0;
        chan->rx_credits = le_max_credits;
-       chan->mps = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS);
+       chan->mps = min_t(u16, chan->imtu, le_default_mps);
 
        skb_queue_head_init(&chan->tx_q);
 }
@@ -522,18 +500,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
        switch (chan->chan_type) {
        case L2CAP_CHAN_CONN_ORIENTED:
-               if (conn->hcon->type == LE_LINK) {
-                       if (chan->dcid == L2CAP_CID_ATT) {
-                               chan->omtu = L2CAP_DEFAULT_MTU;
-                               chan->scid = L2CAP_CID_ATT;
-                       } else {
-                               chan->scid = l2cap_alloc_cid(conn);
-                       }
-               } else {
-                       /* Alloc CID for connection-oriented socket */
-                       chan->scid = l2cap_alloc_cid(conn);
+               /* Alloc CID for connection-oriented socket */
+               chan->scid = l2cap_alloc_cid(conn);
+               if (conn->hcon->type == ACL_LINK)
                        chan->omtu = L2CAP_DEFAULT_MTU;
-               }
                break;
 
        case L2CAP_CHAN_CONN_LESS:
@@ -543,11 +513,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
                chan->omtu = L2CAP_DEFAULT_MTU;
                break;
 
-       case L2CAP_CHAN_CONN_FIX_A2MP:
-               chan->scid = L2CAP_CID_A2MP;
-               chan->dcid = L2CAP_CID_A2MP;
-               chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
-               chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+       case L2CAP_CHAN_FIXED:
+               /* Caller will set CID and CID specific MTU values */
                break;
 
        default:
@@ -595,7 +562,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
                chan->conn = NULL;
 
-               if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
+               if (chan->scid != L2CAP_CID_A2MP)
                        hci_conn_drop(conn->hcon);
 
                if (mgr && mgr->bredr_chan == chan)
@@ -642,6 +609,23 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
        return;
 }
 
+void l2cap_conn_update_id_addr(struct hci_conn *hcon)
+{
+       struct l2cap_conn *conn = hcon->l2cap_data;
+       struct l2cap_chan *chan;
+
+       mutex_lock(&conn->chan_lock);
+
+       list_for_each_entry(chan, &conn->chan_l, list) {
+               l2cap_chan_lock(chan);
+               bacpy(&chan->dst, &hcon->dst);
+               chan->dst_type = bdaddr_type(hcon, hcon->dst_type);
+               l2cap_chan_unlock(chan);
+       }
+
+       mutex_unlock(&conn->chan_lock);
+}
+
 static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
@@ -699,10 +683,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 
        case BT_CONNECTED:
        case BT_CONFIG:
-               /* ATT uses L2CAP_CHAN_CONN_ORIENTED so we must also
-                * check for chan->psm.
-                */
-               if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && chan->psm) {
+               if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
                        __set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
                        l2cap_send_disconn_req(chan, reason);
                } else
@@ -737,6 +718,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
        case L2CAP_CHAN_RAW:
                switch (chan->sec_level) {
                case BT_SECURITY_HIGH:
+               case BT_SECURITY_FIPS:
                        return HCI_AT_DEDICATED_BONDING_MITM;
                case BT_SECURITY_MEDIUM:
                        return HCI_AT_DEDICATED_BONDING;
@@ -749,7 +731,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
                        if (chan->sec_level == BT_SECURITY_LOW)
                                chan->sec_level = BT_SECURITY_SDP;
                }
-               if (chan->sec_level == BT_SECURITY_HIGH)
+               if (chan->sec_level == BT_SECURITY_HIGH ||
+                   chan->sec_level == BT_SECURITY_FIPS)
                        return HCI_AT_NO_BONDING_MITM;
                else
                        return HCI_AT_NO_BONDING;
@@ -759,7 +742,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
                        if (chan->sec_level == BT_SECURITY_LOW)
                                chan->sec_level = BT_SECURITY_SDP;
 
-                       if (chan->sec_level == BT_SECURITY_HIGH)
+                       if (chan->sec_level == BT_SECURITY_HIGH ||
+                           chan->sec_level == BT_SECURITY_FIPS)
                                return HCI_AT_NO_BONDING_MITM;
                        else
                                return HCI_AT_NO_BONDING;
@@ -768,6 +752,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
        default:
                switch (chan->sec_level) {
                case BT_SECURITY_HIGH:
+               case BT_SECURITY_FIPS:
                        return HCI_AT_GENERAL_BONDING_MITM;
                case BT_SECURITY_MEDIUM:
                        return HCI_AT_GENERAL_BONDING;
@@ -1330,7 +1315,7 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err)
                __clear_ack_timer(chan);
        }
 
-       if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+       if (chan->scid == L2CAP_CID_A2MP) {
                l2cap_state_change(chan, BT_DISCONN);
                return;
        }
@@ -1493,8 +1478,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
        if (!chan)
                goto clean;
 
-       chan->dcid = L2CAP_CID_ATT;
-
        bacpy(&chan->src, &hcon->src);
        bacpy(&chan->dst, &hcon->dst);
        chan->src_type = bdaddr_type(hcon, hcon->src_type);
@@ -1528,7 +1511,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
                l2cap_chan_lock(chan);
 
-               if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+               if (chan->scid == L2CAP_CID_A2MP) {
                        l2cap_chan_unlock(chan);
                        continue;
                }
@@ -1546,6 +1529,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
        }
 
        mutex_unlock(&conn->chan_lock);
+
+       queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
 }
 
 /* Notify sockets that we cannot guaranty reliability anymore */
@@ -1671,6 +1656,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
        kfree_skb(conn->rx_skb);
 
+       skb_queue_purge(&conn->pending_rx);
+       flush_work(&conn->pending_rx_work);
+
        l2cap_unregister_all_users(conn);
 
        mutex_lock(&conn->chan_lock);
@@ -1718,66 +1706,6 @@ static void security_timeout(struct work_struct *work)
        }
 }
 
-static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
-{
-       struct l2cap_conn *conn = hcon->l2cap_data;
-       struct hci_chan *hchan;
-
-       if (conn)
-               return conn;
-
-       hchan = hci_chan_create(hcon);
-       if (!hchan)
-               return NULL;
-
-       conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL);
-       if (!conn) {
-               hci_chan_del(hchan);
-               return NULL;
-       }
-
-       kref_init(&conn->ref);
-       hcon->l2cap_data = conn;
-       conn->hcon = hcon;
-       hci_conn_get(conn->hcon);
-       conn->hchan = hchan;
-
-       BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
-
-       switch (hcon->type) {
-       case LE_LINK:
-               if (hcon->hdev->le_mtu) {
-                       conn->mtu = hcon->hdev->le_mtu;
-                       break;
-               }
-               /* fall through */
-       default:
-               conn->mtu = hcon->hdev->acl_mtu;
-               break;
-       }
-
-       conn->feat_mask = 0;
-
-       if (hcon->type == ACL_LINK)
-               conn->hs_enabled = test_bit(HCI_HS_ENABLED,
-                                           &hcon->hdev->dev_flags);
-
-       spin_lock_init(&conn->lock);
-       mutex_init(&conn->chan_lock);
-
-       INIT_LIST_HEAD(&conn->chan_l);
-       INIT_LIST_HEAD(&conn->users);
-
-       if (hcon->type == LE_LINK)
-               INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
-       else
-               INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
-
-       conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
-
-       return conn;
-}
-
 static void l2cap_conn_free(struct kref *ref)
 {
        struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref);
@@ -1848,154 +1776,6 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
        return c1;
 }
 
-static bool is_valid_psm(u16 psm, u8 dst_type)
-{
-       if (!psm)
-               return false;
-
-       if (bdaddr_type_is_le(dst_type))
-               return (psm <= 0x00ff);
-
-       /* PSM must be odd and lsb of upper byte must be 0 */
-       return ((psm & 0x0101) == 0x0001);
-}
-
-int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
-                      bdaddr_t *dst, u8 dst_type)
-{
-       struct l2cap_conn *conn;
-       struct hci_conn *hcon;
-       struct hci_dev *hdev;
-       __u8 auth_type;
-       int err;
-
-       BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst,
-              dst_type, __le16_to_cpu(psm));
-
-       hdev = hci_get_route(dst, &chan->src);
-       if (!hdev)
-               return -EHOSTUNREACH;
-
-       hci_dev_lock(hdev);
-
-       l2cap_chan_lock(chan);
-
-       if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
-           chan->chan_type != L2CAP_CHAN_RAW) {
-               err = -EINVAL;
-               goto done;
-       }
-
-       if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
-               err = -EINVAL;
-               goto done;
-       }
-
-       switch (chan->mode) {
-       case L2CAP_MODE_BASIC:
-               break;
-       case L2CAP_MODE_LE_FLOWCTL:
-               l2cap_le_flowctl_init(chan);
-               break;
-       case L2CAP_MODE_ERTM:
-       case L2CAP_MODE_STREAMING:
-               if (!disable_ertm)
-                       break;
-               /* fall through */
-       default:
-               err = -ENOTSUPP;
-               goto done;
-       }
-
-       switch (chan->state) {
-       case BT_CONNECT:
-       case BT_CONNECT2:
-       case BT_CONFIG:
-               /* Already connecting */
-               err = 0;
-               goto done;
-
-       case BT_CONNECTED:
-               /* Already connected */
-               err = -EISCONN;
-               goto done;
-
-       case BT_OPEN:
-       case BT_BOUND:
-               /* Can connect */
-               break;
-
-       default:
-               err = -EBADFD;
-               goto done;
-       }
-
-       /* Set destination address and psm */
-       bacpy(&chan->dst, dst);
-       chan->dst_type = dst_type;
-
-       chan->psm = psm;
-       chan->dcid = cid;
-
-       auth_type = l2cap_get_auth_type(chan);
-
-       if (bdaddr_type_is_le(dst_type))
-               hcon = hci_connect(hdev, LE_LINK, dst, dst_type,
-                                  chan->sec_level, auth_type);
-       else
-               hcon = hci_connect(hdev, ACL_LINK, dst, dst_type,
-                                  chan->sec_level, auth_type);
-
-       if (IS_ERR(hcon)) {
-               err = PTR_ERR(hcon);
-               goto done;
-       }
-
-       conn = l2cap_conn_add(hcon);
-       if (!conn) {
-               hci_conn_drop(hcon);
-               err = -ENOMEM;
-               goto done;
-       }
-
-       if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
-               hci_conn_drop(hcon);
-               err = -EBUSY;
-               goto done;
-       }
-
-       /* Update source addr of the socket */
-       bacpy(&chan->src, &hcon->src);
-       chan->src_type = bdaddr_type(hcon, hcon->src_type);
-
-       l2cap_chan_unlock(chan);
-       l2cap_chan_add(conn, chan);
-       l2cap_chan_lock(chan);
-
-       /* l2cap_chan_add takes its own ref so we can drop this one */
-       hci_conn_drop(hcon);
-
-       l2cap_state_change(chan, BT_CONNECT);
-       __set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
-
-       if (hcon->state == BT_CONNECTED) {
-               if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
-                       __clear_chan_timer(chan);
-                       if (l2cap_chan_check_security(chan))
-                               l2cap_state_change(chan, BT_CONNECTED);
-               } else
-                       l2cap_do_start(chan);
-       }
-
-       err = 0;
-
-done:
-       l2cap_chan_unlock(chan);
-       hci_dev_unlock(hdev);
-       hci_dev_put(hdev);
-       return err;
-}
-
 static void l2cap_monitor_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
@@ -2654,6 +2434,14 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
+               /* Channel lock is released before requesting new skb and then
+                * reacquired thus we need to recheck channel state.
+                */
+               if (chan->state != BT_CONNECTED) {
+                       kfree_skb(skb);
+                       return -ENOTCONN;
+               }
+
                l2cap_do_send(chan, skb);
                return len;
        }
@@ -2703,6 +2491,14 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
+               /* Channel lock is released before requesting new skb and then
+                * reacquired thus we need to recheck channel state.
+                */
+               if (chan->state != BT_CONNECTED) {
+                       kfree_skb(skb);
+                       return -ENOTCONN;
+               }
+
                l2cap_do_send(chan, skb);
                err = len;
                break;
@@ -5709,7 +5505,7 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
 {
        struct l2cap_le_credits *pkt;
        struct l2cap_chan *chan;
-       u16 cid, credits;
+       u16 cid, credits, max_credits;
 
        if (cmd_len != sizeof(*pkt))
                return -EPROTO;
@@ -5724,6 +5520,17 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
        if (!chan)
                return -EBADSLT;
 
+       max_credits = LE_FLOWCTL_MAX_CREDITS - chan->tx_credits;
+       if (credits > max_credits) {
+               BT_ERR("LE credits overflow");
+               l2cap_send_disconn_req(chan, ECONNRESET);
+
+               /* Return 0 so that we don't trigger an unnecessary
+                * command reject packet.
+                */
+               return 0;
+       }
+
        chan->tx_credits += credits;
 
        while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) {
@@ -5770,17 +5577,6 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
 {
        int err = 0;
 
-       if (!enable_lecoc) {
-               switch (cmd->code) {
-               case L2CAP_LE_CONN_REQ:
-               case L2CAP_LE_CONN_RSP:
-               case L2CAP_LE_CREDITS:
-               case L2CAP_DISCONN_REQ:
-               case L2CAP_DISCONN_RSP:
-                       return -EINVAL;
-               }
-       }
-
        switch (cmd->code) {
        case L2CAP_COMMAND_REJ:
                l2cap_le_command_rej(conn, cmd, cmd_len, data);
@@ -6871,6 +6667,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
 
        if (!chan->rx_credits) {
                BT_ERR("No credits to receive LE L2CAP data");
+               l2cap_send_disconn_req(chan, ECONNRESET);
                return -ENOBUFS;
        }
 
@@ -6995,8 +6792,10 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
                 * But we don't have any other choice. L2CAP doesn't
                 * provide flow control mechanism. */
 
-               if (chan->imtu < skb->len)
+               if (chan->imtu < skb->len) {
+                       BT_ERR("Dropping L2CAP data: receive buffer overflow");
                        goto drop;
+               }
 
                if (!chan->ops->recv(chan, skb))
                        goto done;
@@ -7084,9 +6883,16 @@ drop:
 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct l2cap_hdr *lh = (void *) skb->data;
+       struct hci_conn *hcon = conn->hcon;
        u16 cid, len;
        __le16 psm;
 
+       if (hcon->state != BT_CONNECTED) {
+               BT_DBG("queueing pending rx skb");
+               skb_queue_tail(&conn->pending_rx, skb);
+               return;
+       }
+
        skb_pull(skb, L2CAP_HDR_SIZE);
        cid = __le16_to_cpu(lh->cid);
        len = __le16_to_cpu(lh->len);
@@ -7132,6 +6938,247 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
        }
 }
 
+static void process_pending_rx(struct work_struct *work)
+{
+       struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+                                              pending_rx_work);
+       struct sk_buff *skb;
+
+       BT_DBG("");
+
+       while ((skb = skb_dequeue(&conn->pending_rx)))
+               l2cap_recv_frame(conn, skb);
+}
+
+static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
+{
+       struct l2cap_conn *conn = hcon->l2cap_data;
+       struct hci_chan *hchan;
+
+       if (conn)
+               return conn;
+
+       hchan = hci_chan_create(hcon);
+       if (!hchan)
+               return NULL;
+
+       conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL);
+       if (!conn) {
+               hci_chan_del(hchan);
+               return NULL;
+       }
+
+       kref_init(&conn->ref);
+       hcon->l2cap_data = conn;
+       conn->hcon = hcon;
+       hci_conn_get(conn->hcon);
+       conn->hchan = hchan;
+
+       BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
+
+       switch (hcon->type) {
+       case LE_LINK:
+               if (hcon->hdev->le_mtu) {
+                       conn->mtu = hcon->hdev->le_mtu;
+                       break;
+               }
+               /* fall through */
+       default:
+               conn->mtu = hcon->hdev->acl_mtu;
+               break;
+       }
+
+       conn->feat_mask = 0;
+
+       if (hcon->type == ACL_LINK)
+               conn->hs_enabled = test_bit(HCI_HS_ENABLED,
+                                           &hcon->hdev->dev_flags);
+
+       spin_lock_init(&conn->lock);
+       mutex_init(&conn->chan_lock);
+
+       INIT_LIST_HEAD(&conn->chan_l);
+       INIT_LIST_HEAD(&conn->users);
+
+       if (hcon->type == LE_LINK)
+               INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
+       else
+               INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
+
+       skb_queue_head_init(&conn->pending_rx);
+       INIT_WORK(&conn->pending_rx_work, process_pending_rx);
+
+       conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
+
+       return conn;
+}
+
+static bool is_valid_psm(u16 psm, u8 dst_type) {
+       if (!psm)
+               return false;
+
+       if (bdaddr_type_is_le(dst_type))
+               return (psm <= 0x00ff);
+
+       /* PSM must be odd and lsb of upper byte must be 0 */
+       return ((psm & 0x0101) == 0x0001);
+}
+
+int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
+                      bdaddr_t *dst, u8 dst_type)
+{
+       struct l2cap_conn *conn;
+       struct hci_conn *hcon;
+       struct hci_dev *hdev;
+       __u8 auth_type;
+       int err;
+
+       BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst,
+              dst_type, __le16_to_cpu(psm));
+
+       hdev = hci_get_route(dst, &chan->src);
+       if (!hdev)
+               return -EHOSTUNREACH;
+
+       hci_dev_lock(hdev);
+
+       l2cap_chan_lock(chan);
+
+       if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
+           chan->chan_type != L2CAP_CHAN_RAW) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !psm) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       if (chan->chan_type == L2CAP_CHAN_FIXED && !cid) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       switch (chan->mode) {
+       case L2CAP_MODE_BASIC:
+               break;
+       case L2CAP_MODE_LE_FLOWCTL:
+               l2cap_le_flowctl_init(chan);
+               break;
+       case L2CAP_MODE_ERTM:
+       case L2CAP_MODE_STREAMING:
+               if (!disable_ertm)
+                       break;
+               /* fall through */
+       default:
+               err = -ENOTSUPP;
+               goto done;
+       }
+
+       switch (chan->state) {
+       case BT_CONNECT:
+       case BT_CONNECT2:
+       case BT_CONFIG:
+               /* Already connecting */
+               err = 0;
+               goto done;
+
+       case BT_CONNECTED:
+               /* Already connected */
+               err = -EISCONN;
+               goto done;
+
+       case BT_OPEN:
+       case BT_BOUND:
+               /* Can connect */
+               break;
+
+       default:
+               err = -EBADFD;
+               goto done;
+       }
+
+       /* Set destination address and psm */
+       bacpy(&chan->dst, dst);
+       chan->dst_type = dst_type;
+
+       chan->psm = psm;
+       chan->dcid = cid;
+
+       auth_type = l2cap_get_auth_type(chan);
+
+       if (bdaddr_type_is_le(dst_type)) {
+               /* Convert from L2CAP channel address type to HCI address type
+                */
+               if (dst_type == BDADDR_LE_PUBLIC)
+                       dst_type = ADDR_LE_DEV_PUBLIC;
+               else
+                       dst_type = ADDR_LE_DEV_RANDOM;
+
+               hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level,
+                                     auth_type);
+       } else {
+               hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type);
+       }
+
+       if (IS_ERR(hcon)) {
+               err = PTR_ERR(hcon);
+               goto done;
+       }
+
+       conn = l2cap_conn_add(hcon);
+       if (!conn) {
+               hci_conn_drop(hcon);
+               err = -ENOMEM;
+               goto done;
+       }
+
+       if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
+               hci_conn_drop(hcon);
+               err = -EBUSY;
+               goto done;
+       }
+
+       /* Update source addr of the socket */
+       bacpy(&chan->src, &hcon->src);
+       chan->src_type = bdaddr_type(hcon, hcon->src_type);
+
+       l2cap_chan_unlock(chan);
+       l2cap_chan_add(conn, chan);
+       l2cap_chan_lock(chan);
+
+       /* l2cap_chan_add takes its own ref so we can drop this one */
+       hci_conn_drop(hcon);
+
+       l2cap_state_change(chan, BT_CONNECT);
+       __set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
+
+       /* Release chan->sport so that it can be reused by other
+        * sockets (as it's only used for listening sockets).
+        */
+       write_lock(&chan_list_lock);
+       chan->sport = 0;
+       write_unlock(&chan_list_lock);
+
+       if (hcon->state == BT_CONNECTED) {
+               if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
+                       __clear_chan_timer(chan);
+                       if (l2cap_chan_check_security(chan))
+                               l2cap_state_change(chan, BT_CONNECTED);
+               } else
+                       l2cap_do_start(chan);
+       }
+
+       err = 0;
+
+done:
+       l2cap_chan_unlock(chan);
+       hci_dev_unlock(hdev);
+       hci_dev_put(hdev);
+       return err;
+}
+
 /* ---- L2CAP interface with lower layer (HCI) ---- */
 
 int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
@@ -7206,7 +7253,8 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
        if (encrypt == 0x00) {
                if (chan->sec_level == BT_SECURITY_MEDIUM) {
                        __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
-               } else if (chan->sec_level == BT_SECURITY_HIGH)
+               } else if (chan->sec_level == BT_SECURITY_HIGH ||
+                          chan->sec_level == BT_SECURITY_FIPS)
                        l2cap_chan_close(chan, ECONNREFUSED);
        } else {
                if (chan->sec_level == BT_SECURITY_MEDIUM)
@@ -7226,7 +7274,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
        if (hcon->type == LE_LINK) {
                if (!status && encrypt)
-                       smp_distribute_keys(conn, 0);
+                       smp_distribute_keys(conn);
                cancel_delayed_work(&conn->security_timer);
        }
 
@@ -7238,7 +7286,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
                       state_to_string(chan->state));
 
-               if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+               if (chan->scid == L2CAP_CID_A2MP) {
                        l2cap_chan_unlock(chan);
                        continue;
                }
index d58f76bcebd1e6866183360f778881f8e84d49b3..b247f9d27fed96dd1e3355265ed4ba6e0861138c 100644 (file)
@@ -36,8 +36,6 @@
 
 #include "smp.h"
 
-bool enable_lecoc;
-
 static struct bt_sock_list l2cap_sk_list = {
        .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
 };
@@ -101,9 +99,16 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
        if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
                return -EINVAL;
 
+       if (la.l2_cid) {
+               /* When the socket gets created it defaults to
+                * CHAN_CONN_ORIENTED, so we need to overwrite the
+                * default here.
+                */
+               chan->chan_type = L2CAP_CHAN_FIXED;
+               chan->omtu = L2CAP_DEFAULT_MTU;
+       }
+
        if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
-               if (!enable_lecoc && la.l2_psm)
-                       return -EINVAL;
                /* We only allow ATT user space socket */
                if (la.l2_cid &&
                    la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
@@ -220,8 +225,6 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
                return -EINVAL;
 
        if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
-               if (!enable_lecoc && la.l2_psm)
-                       return -EINVAL;
                /* We only allow ATT user space socket */
                if (la.l2_cid &&
                    la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
@@ -357,17 +360,20 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
+       if (peer && sk->sk_state != BT_CONNECTED)
+               return -ENOTCONN;
+
        memset(la, 0, sizeof(struct sockaddr_l2));
        addr->sa_family = AF_BLUETOOTH;
        *len = sizeof(struct sockaddr_l2);
 
+       la->l2_psm = chan->psm;
+
        if (peer) {
-               la->l2_psm = chan->psm;
                bacpy(&la->l2_bdaddr, &chan->dst);
                la->l2_cid = cpu_to_le16(chan->dcid);
                la->l2_bdaddr_type = chan->dst_type;
        } else {
-               la->l2_psm = chan->sport;
                bacpy(&la->l2_bdaddr, &chan->src);
                la->l2_cid = cpu_to_le16(chan->scid);
                la->l2_bdaddr_type = chan->src_type;
@@ -432,6 +438,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
                        opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
                              L2CAP_LM_SECURE;
                        break;
+               case BT_SECURITY_FIPS:
+                       opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
+                             L2CAP_LM_SECURE | L2CAP_LM_FIPS;
+                       break;
                default:
                        opt = 0;
                        break;
@@ -445,6 +455,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
 
                if (put_user(opt, (u32 __user *) optval))
                        err = -EFAULT;
+
                break;
 
        case L2CAP_CONNINFO:
@@ -499,6 +510,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
        switch (optname) {
        case BT_SECURITY:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
+                   chan->chan_type != L2CAP_CHAN_FIXED &&
                    chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
@@ -560,11 +572,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
                break;
 
        case BT_SNDMTU:
-               if (!enable_lecoc) {
-                       err = -EPROTONOSUPPORT;
-                       break;
-               }
-
                if (!bdaddr_type_is_le(chan->src_type)) {
                        err = -EINVAL;
                        break;
@@ -580,11 +587,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
                break;
 
        case BT_RCVMTU:
-               if (!enable_lecoc) {
-                       err = -EPROTONOSUPPORT;
-                       break;
-               }
-
                if (!bdaddr_type_is_le(chan->src_type)) {
                        err = -EINVAL;
                        break;
@@ -699,6 +701,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
                        break;
                }
 
+               if (opt & L2CAP_LM_FIPS) {
+                       err = -EINVAL;
+                       break;
+               }
+
                if (opt & L2CAP_LM_AUTH)
                        chan->sec_level = BT_SECURITY_LOW;
                if (opt & L2CAP_LM_ENCRYPT)
@@ -750,6 +757,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
        switch (optname) {
        case BT_SECURITY:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
+                   chan->chan_type != L2CAP_CHAN_FIXED &&
                    chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
@@ -895,11 +903,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
                break;
 
        case BT_SNDMTU:
-               if (!enable_lecoc) {
-                       err = -EPROTONOSUPPORT;
-                       break;
-               }
-
                if (!bdaddr_type_is_le(chan->src_type)) {
                        err = -EINVAL;
                        break;
@@ -912,11 +915,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
                break;
 
        case BT_RCVMTU:
-               if (!enable_lecoc) {
-                       err = -EPROTONOSUPPORT;
-                       break;
-               }
-
                if (!bdaddr_type_is_le(chan->src_type)) {
                        err = -EINVAL;
                        break;
@@ -1449,6 +1447,11 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
                chan->tx_credits = pchan->tx_credits;
                chan->rx_credits = pchan->rx_credits;
 
+               if (chan->chan_type == L2CAP_CHAN_FIXED) {
+                       chan->scid = pchan->scid;
+                       chan->dcid = pchan->scid;
+               }
+
                security_sk_clone(parent, sk);
        } else {
                switch (sk->sk_type) {
@@ -1614,6 +1617,3 @@ void l2cap_cleanup_sockets(void)
        bt_sock_unregister(BTPROTO_L2CAP);
        proto_unregister(&l2cap_proto);
 }
-
-module_param(enable_lecoc, bool, 0644);
-MODULE_PARM_DESC(enable_lecoc, "Enable support for LE CoC");
index a03ca3ca91bfa77e2663a09f90ce2271addb2331..98e9df3556e71504063b4ac3c59d4f6775cb2451 100644 (file)
@@ -34,7 +34,7 @@
 #include "smp.h"
 
 #define MGMT_VERSION   1
-#define MGMT_REVISION  4
+#define MGMT_REVISION  5
 
 static const u16 mgmt_commands[] = {
        MGMT_OP_READ_INDEX_LIST,
@@ -79,6 +79,10 @@ static const u16 mgmt_commands[] = {
        MGMT_OP_SET_BREDR,
        MGMT_OP_SET_STATIC_ADDRESS,
        MGMT_OP_SET_SCAN_PARAMS,
+       MGMT_OP_SET_SECURE_CONN,
+       MGMT_OP_SET_DEBUG_KEYS,
+       MGMT_OP_SET_PRIVACY,
+       MGMT_OP_LOAD_IRKS,
 };
 
 static const u16 mgmt_events[] = {
@@ -103,6 +107,7 @@ static const u16 mgmt_events[] = {
        MGMT_EV_DEVICE_UNBLOCKED,
        MGMT_EV_DEVICE_UNPAIRED,
        MGMT_EV_PASSKEY_NOTIFY,
+       MGMT_EV_NEW_IRK,
 };
 
 #define CACHE_TIMEOUT  msecs_to_jiffies(2 * 1000)
@@ -127,7 +132,7 @@ static u8 mgmt_status_table[] = {
        MGMT_STATUS_FAILED,             /* Hardware Failure */
        MGMT_STATUS_CONNECT_FAILED,     /* Page Timeout */
        MGMT_STATUS_AUTH_FAILED,        /* Authentication Failed */
-       MGMT_STATUS_NOT_PAIRED,         /* PIN or Key Missing */
+       MGMT_STATUS_AUTH_FAILED,        /* PIN or Key Missing */
        MGMT_STATUS_NO_RESOURCES,       /* Memory Full */
        MGMT_STATUS_TIMEOUT,            /* Connection Timeout */
        MGMT_STATUS_NO_RESOURCES,       /* Max Number of Connections */
@@ -363,6 +368,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
 
        settings |= MGMT_SETTING_POWERED;
        settings |= MGMT_SETTING_PAIRABLE;
+       settings |= MGMT_SETTING_DEBUG_KEYS;
 
        if (lmp_bredr_capable(hdev)) {
                settings |= MGMT_SETTING_CONNECTABLE;
@@ -376,11 +382,16 @@ static u32 get_supported_settings(struct hci_dev *hdev)
                        settings |= MGMT_SETTING_SSP;
                        settings |= MGMT_SETTING_HS;
                }
+
+               if (lmp_sc_capable(hdev) ||
+                   test_bit(HCI_FORCE_SC, &hdev->dev_flags))
+                       settings |= MGMT_SETTING_SECURE_CONN;
        }
 
        if (lmp_le_capable(hdev)) {
                settings |= MGMT_SETTING_LE;
                settings |= MGMT_SETTING_ADVERTISING;
+               settings |= MGMT_SETTING_PRIVACY;
        }
 
        return settings;
@@ -423,6 +434,15 @@ static u32 get_current_settings(struct hci_dev *hdev)
        if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
                settings |= MGMT_SETTING_ADVERTISING;
 
+       if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
+               settings |= MGMT_SETTING_SECURE_CONN;
+
+       if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags))
+               settings |= MGMT_SETTING_DEBUG_KEYS;
+
+       if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
+               settings |= MGMT_SETTING_PRIVACY;
+
        return settings;
 }
 
@@ -629,14 +649,8 @@ static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
 
        flags |= get_adv_discov_flags(hdev);
 
-       if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
-               if (lmp_le_br_capable(hdev))
-                       flags |= LE_AD_SIM_LE_BREDR_CTRL;
-               if (lmp_host_le_br_capable(hdev))
-                       flags |= LE_AD_SIM_LE_BREDR_HOST;
-       } else {
+       if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
                flags |= LE_AD_NO_BREDR;
-       }
 
        if (flags) {
                BT_DBG("adv flags 0x%02x", flags);
@@ -803,6 +817,64 @@ static void update_class(struct hci_request *req)
        hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
 }
 
+static bool get_connectable(struct hci_dev *hdev)
+{
+       struct pending_cmd *cmd;
+
+       /* If there's a pending mgmt command the flag will not yet have
+        * it's final value, so check for this first.
+        */
+       cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
+       if (cmd) {
+               struct mgmt_mode *cp = cmd->param;
+               return cp->val;
+       }
+
+       return test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
+}
+
+static void enable_advertising(struct hci_request *req)
+{
+       struct hci_dev *hdev = req->hdev;
+       struct hci_cp_le_set_adv_param cp;
+       u8 own_addr_type, enable = 0x01;
+       bool connectable;
+
+       /* Clear the HCI_ADVERTISING bit temporarily so that the
+        * hci_update_random_address knows that it's safe to go ahead
+        * and write a new random address. The flag will be set back on
+        * as soon as the SET_ADV_ENABLE HCI command completes.
+        */
+       clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
+
+       connectable = get_connectable(hdev);
+
+       /* Set require_privacy to true only when non-connectable
+        * advertising is used. In that case it is fine to use a
+        * non-resolvable private address.
+        */
+       if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
+               return;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.min_interval = __constant_cpu_to_le16(0x0800);
+       cp.max_interval = __constant_cpu_to_le16(0x0800);
+       cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
+       cp.own_address_type = own_addr_type;
+       cp.channel_map = hdev->le_adv_channel_map;
+
+       hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
+
+       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
+}
+
+static void disable_advertising(struct hci_request *req)
+{
+       u8 enable = 0x00;
+
+       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
+}
+
 static void service_cache_off(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
@@ -824,12 +896,39 @@ static void service_cache_off(struct work_struct *work)
        hci_req_run(&req, NULL);
 }
 
+static void rpa_expired(struct work_struct *work)
+{
+       struct hci_dev *hdev = container_of(work, struct hci_dev,
+                                           rpa_expired.work);
+       struct hci_request req;
+
+       BT_DBG("");
+
+       set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
+
+       if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags) ||
+           hci_conn_num(hdev, LE_LINK) > 0)
+               return;
+
+       /* The generation of a new RPA and programming it into the
+        * controller happens in the enable_advertising() function.
+        */
+
+       hci_req_init(&req, hdev);
+
+       disable_advertising(&req);
+       enable_advertising(&req);
+
+       hci_req_run(&req, NULL);
+}
+
 static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
 {
        if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
                return;
 
        INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
+       INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
 
        /* Non-mgmt controlled devices get this bit set
         * implicitly so that pairing works for them, however
@@ -935,6 +1034,71 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
                            sizeof(settings));
 }
 
+static void clean_up_hci_complete(struct hci_dev *hdev, u8 status)
+{
+       BT_DBG("%s status 0x%02x", hdev->name, status);
+
+       if (hci_conn_count(hdev) == 0) {
+               cancel_delayed_work(&hdev->power_off);
+               queue_work(hdev->req_workqueue, &hdev->power_off.work);
+       }
+}
+
+static int clean_up_hci_state(struct hci_dev *hdev)
+{
+       struct hci_request req;
+       struct hci_conn *conn;
+
+       hci_req_init(&req, hdev);
+
+       if (test_bit(HCI_ISCAN, &hdev->flags) ||
+           test_bit(HCI_PSCAN, &hdev->flags)) {
+               u8 scan = 0x00;
+               hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+       }
+
+       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
+               disable_advertising(&req);
+
+       if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
+               hci_req_add_le_scan_disable(&req);
+       }
+
+       list_for_each_entry(conn, &hdev->conn_hash.list, list) {
+               struct hci_cp_disconnect dc;
+               struct hci_cp_reject_conn_req rej;
+
+               switch (conn->state) {
+               case BT_CONNECTED:
+               case BT_CONFIG:
+                       dc.handle = cpu_to_le16(conn->handle);
+                       dc.reason = 0x15; /* Terminated due to Power Off */
+                       hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
+                       break;
+               case BT_CONNECT:
+                       if (conn->type == LE_LINK)
+                               hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
+                                           0, NULL);
+                       else if (conn->type == ACL_LINK)
+                               hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
+                                           6, &conn->dst);
+                       break;
+               case BT_CONNECT2:
+                       bacpy(&rej.bdaddr, &conn->dst);
+                       rej.reason = 0x15; /* Terminated due to Power Off */
+                       if (conn->type == ACL_LINK)
+                               hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
+                                           sizeof(rej), &rej);
+                       else if (conn->type == SCO_LINK)
+                               hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
+                                           sizeof(rej), &rej);
+                       break;
+               }
+       }
+
+       return hci_req_run(&req, clean_up_hci_complete);
+}
+
 static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
                       u16 len)
 {
@@ -978,12 +1142,23 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
                goto failed;
        }
 
-       if (cp->val)
+       if (cp->val) {
                queue_work(hdev->req_workqueue, &hdev->power_on);
-       else
-               queue_work(hdev->req_workqueue, &hdev->power_off.work);
-
-       err = 0;
+               err = 0;
+       } else {
+               /* Disconnect connections, stop scans, etc */
+               err = clean_up_hci_state(hdev);
+               if (!err)
+                       queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
+                                          HCI_POWER_OFF_TIMEOUT);
+
+               /* ENODATA means there were no HCI commands queued */
+               if (err == -ENODATA) {
+                       cancel_delayed_work(&hdev->power_off);
+                       queue_work(hdev->req_workqueue, &hdev->power_off.work);
+                       err = 0;
+               }
+       }
 
 failed:
        hci_dev_unlock(hdev);
@@ -1336,50 +1511,6 @@ static void write_fast_connectable(struct hci_request *req, bool enable)
                hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
 }
 
-static u8 get_adv_type(struct hci_dev *hdev)
-{
-       struct pending_cmd *cmd;
-       bool connectable;
-
-       /* If there's a pending mgmt command the flag will not yet have
-        * it's final value, so check for this first.
-        */
-       cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
-       if (cmd) {
-               struct mgmt_mode *cp = cmd->param;
-               connectable = !!cp->val;
-       } else {
-               connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
-       }
-
-       return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
-}
-
-static void enable_advertising(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-       struct hci_cp_le_set_adv_param cp;
-       u8 enable = 0x01;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.min_interval = __constant_cpu_to_le16(0x0800);
-       cp.max_interval = __constant_cpu_to_le16(0x0800);
-       cp.type = get_adv_type(hdev);
-       cp.own_address_type = hdev->own_addr_type;
-       cp.channel_map = 0x07;
-
-       hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
-
-       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
-}
-
-static void disable_advertising(struct hci_request *req)
-{
-       u8 enable = 0x00;
-
-       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
-}
-
 static void set_connectable_complete(struct hci_dev *hdev, u8 status)
 {
        struct pending_cmd *cmd;
@@ -2065,7 +2196,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
-               err = hci_uuids_clear(hdev);
+               hci_uuids_clear(hdev);
 
                if (enable_service_cache(hdev)) {
                        err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
@@ -2205,6 +2336,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
 {
        struct mgmt_cp_load_link_keys *cp = data;
        u16 key_count, expected_len;
+       bool changed;
        int i;
 
        BT_DBG("request for %s", hdev->name);
@@ -2234,7 +2366,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
        for (i = 0; i < key_count; i++) {
                struct mgmt_link_key_info *key = &cp->keys[i];
 
-               if (key->addr.type != BDADDR_BREDR)
+               if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
                        return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
                                          MGMT_STATUS_INVALID_PARAMS);
        }
@@ -2244,9 +2376,12 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
        hci_link_keys_clear(hdev);
 
        if (cp->debug_keys)
-               set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+               changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
        else
-               clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+               changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+
+       if (changed)
+               new_settings(hdev, NULL);
 
        for (i = 0; i < key_count; i++) {
                struct mgmt_link_key_info *key = &cp->keys[i];
@@ -2306,10 +2441,22 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
                goto unlock;
        }
 
-       if (cp->addr.type == BDADDR_BREDR)
+       if (cp->addr.type == BDADDR_BREDR) {
                err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
-       else
-               err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
+       } else {
+               u8 addr_type;
+
+               if (cp->addr.type == BDADDR_LE_PUBLIC)
+                       addr_type = ADDR_LE_DEV_PUBLIC;
+               else
+                       addr_type = ADDR_LE_DEV_RANDOM;
+
+               hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
+
+               hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
+
+               err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
+       }
 
        if (err < 0) {
                err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
@@ -2633,6 +2780,16 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
        mgmt_pending_remove(cmd);
 }
 
+void mgmt_smp_complete(struct hci_conn *conn, bool complete)
+{
+       u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
+       struct pending_cmd *cmd;
+
+       cmd = find_pairing(conn);
+       if (cmd)
+               pairing_complete(cmd, status);
+}
+
 static void pairing_complete_cb(struct hci_conn *conn, u8 status)
 {
        struct pending_cmd *cmd;
@@ -2646,7 +2803,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status)
                pairing_complete(cmd, mgmt_status(status));
 }
 
-static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
+static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
 {
        struct pending_cmd *cmd;
 
@@ -2697,12 +2854,22 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        else
                auth_type = HCI_AT_DEDICATED_BONDING_MITM;
 
-       if (cp->addr.type == BDADDR_BREDR)
-               conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
-                                  cp->addr.type, sec_level, auth_type);
-       else
-               conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
-                                  cp->addr.type, sec_level, auth_type);
+       if (cp->addr.type == BDADDR_BREDR) {
+               conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
+                                      auth_type);
+       } else {
+               u8 addr_type;
+
+               /* Convert from L2CAP channel address type to HCI address type
+                */
+               if (cp->addr.type == BDADDR_LE_PUBLIC)
+                       addr_type = ADDR_LE_DEV_PUBLIC;
+               else
+                       addr_type = ADDR_LE_DEV_RANDOM;
+
+               conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
+                                     sec_level, auth_type);
+       }
 
        if (IS_ERR(conn)) {
                int status;
@@ -2733,13 +2900,16 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        /* For LE, just connecting isn't a proof that the pairing finished */
-       if (cp->addr.type == BDADDR_BREDR)
+       if (cp->addr.type == BDADDR_BREDR) {
                conn->connect_cfm_cb = pairing_complete_cb;
-       else
-               conn->connect_cfm_cb = le_connect_complete_cb;
+               conn->security_cfm_cb = pairing_complete_cb;
+               conn->disconn_cfm_cb = pairing_complete_cb;
+       } else {
+               conn->connect_cfm_cb = le_pairing_complete_cb;
+               conn->security_cfm_cb = le_pairing_complete_cb;
+               conn->disconn_cfm_cb = le_pairing_complete_cb;
+       }
 
-       conn->security_cfm_cb = pairing_complete_cb;
-       conn->disconn_cfm_cb = pairing_complete_cb;
        conn->io_capability = cp->io_cap;
        cmd->user_data = conn;
 
@@ -3071,7 +3241,12 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
                goto unlock;
        }
 
-       err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
+       if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
+               err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
+                                  0, NULL);
+       else
+               err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
+
        if (err < 0)
                mgmt_pending_remove(cmd);
 
@@ -3083,23 +3258,46 @@ unlock:
 static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
                               void *data, u16 len)
 {
-       struct mgmt_cp_add_remote_oob_data *cp = data;
-       u8 status;
        int err;
 
        BT_DBG("%s ", hdev->name);
 
        hci_dev_lock(hdev);
 
-       err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
-                                     cp->randomizer);
-       if (err < 0)
-               status = MGMT_STATUS_FAILED;
-       else
-               status = MGMT_STATUS_SUCCESS;
+       if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
+               struct mgmt_cp_add_remote_oob_data *cp = data;
+               u8 status;
 
-       err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
-                          &cp->addr, sizeof(cp->addr));
+               err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
+                                             cp->hash, cp->randomizer);
+               if (err < 0)
+                       status = MGMT_STATUS_FAILED;
+               else
+                       status = MGMT_STATUS_SUCCESS;
+
+               err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
+                                  status, &cp->addr, sizeof(cp->addr));
+       } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
+               struct mgmt_cp_add_remote_oob_ext_data *cp = data;
+               u8 status;
+
+               err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
+                                                 cp->hash192,
+                                                 cp->randomizer192,
+                                                 cp->hash256,
+                                                 cp->randomizer256);
+               if (err < 0)
+                       status = MGMT_STATUS_FAILED;
+               else
+                       status = MGMT_STATUS_SUCCESS;
+
+               err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
+                                  status, &cp->addr, sizeof(cp->addr));
+       } else {
+               BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
+               err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
+                                MGMT_STATUS_INVALID_PARAMS);
+       }
 
        hci_dev_unlock(hdev);
        return err;
@@ -3195,7 +3393,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
        struct hci_request req;
        /* General inquiry access code (GIAC) */
        u8 lap[3] = { 0x33, 0x8b, 0x9e };
-       u8 status;
+       u8 status, own_addr_type;
        int err;
 
        BT_DBG("%s", hdev->name);
@@ -3280,18 +3478,31 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
                        goto failed;
                }
 
-               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
+               /* If controller is scanning, it means the background scanning
+                * is running. Thus, we should temporarily stop it in order to
+                * set the discovery scanning parameters.
+                */
+               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+                       hci_req_add_le_scan_disable(&req);
+
+               memset(&param_cp, 0, sizeof(param_cp));
+
+               /* All active scans will be done with either a resolvable
+                * private address (when privacy feature has been enabled)
+                * or unresolvable private address.
+                */
+               err = hci_update_random_address(&req, true, &own_addr_type);
+               if (err < 0) {
                        err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
-                                        MGMT_STATUS_BUSY);
+                                        MGMT_STATUS_FAILED);
                        mgmt_pending_remove(cmd);
                        goto failed;
                }
 
-               memset(&param_cp, 0, sizeof(param_cp));
                param_cp.type = LE_SCAN_ACTIVE;
                param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
                param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
-               param_cp.own_address_type = hdev->own_addr_type;
+               param_cp.own_address_type = own_addr_type;
                hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
                            &param_cp);
 
@@ -3361,7 +3572,6 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
        struct hci_cp_remote_name_req_cancel cp;
        struct inquiry_entry *e;
        struct hci_request req;
-       struct hci_cp_le_set_scan_enable enable_cp;
        int err;
 
        BT_DBG("%s", hdev->name);
@@ -3397,10 +3607,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
                } else {
                        cancel_delayed_work(&hdev->le_scan_disable);
 
-                       memset(&enable_cp, 0, sizeof(enable_cp));
-                       enable_cp.enable = LE_SCAN_DISABLE;
-                       hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
-                                   sizeof(enable_cp), &enable_cp);
+                       hci_req_add_le_scan_disable(&req);
                }
 
                break;
@@ -3457,15 +3664,17 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
        hci_dev_lock(hdev);
 
        if (!hci_discovery_active(hdev)) {
-               err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
-                                MGMT_STATUS_FAILED);
+               err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
+                                  MGMT_STATUS_FAILED, &cp->addr,
+                                  sizeof(cp->addr));
                goto failed;
        }
 
        e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
        if (!e) {
-               err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
-                                MGMT_STATUS_INVALID_PARAMS);
+               err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
+                                  MGMT_STATUS_INVALID_PARAMS, &cp->addr,
+                                  sizeof(cp->addr));
                goto failed;
        }
 
@@ -3754,6 +3963,21 @@ static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
 
        err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
 
+       /* If background scan is running, restart it so new parameters are
+        * loaded.
+        */
+       if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
+           hdev->discovery.state == DISCOVERY_STOPPED) {
+               struct hci_request req;
+
+               hci_req_init(&req, hdev);
+
+               hci_req_add_le_scan_disable(&req);
+               hci_req_add_le_passive_scan(&req);
+
+               hci_req_run(&req, NULL);
+       }
+
        hci_dev_unlock(hdev);
 
        return err;
@@ -3999,15 +4223,269 @@ unlock:
        return err;
 }
 
+static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
+                          void *data, u16 len)
+{
+       struct mgmt_mode *cp = data;
+       struct pending_cmd *cmd;
+       u8 val, status;
+       int err;
+
+       BT_DBG("request for %s", hdev->name);
+
+       status = mgmt_bredr_support(hdev);
+       if (status)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
+                                 status);
+
+       if (!lmp_sc_capable(hdev) &&
+           !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
+       if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
+                                 MGMT_STATUS_INVALID_PARAMS);
+
+       hci_dev_lock(hdev);
+
+       if (!hdev_is_powered(hdev)) {
+               bool changed;
+
+               if (cp->val) {
+                       changed = !test_and_set_bit(HCI_SC_ENABLED,
+                                                   &hdev->dev_flags);
+                       if (cp->val == 0x02)
+                               set_bit(HCI_SC_ONLY, &hdev->dev_flags);
+                       else
+                               clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+               } else {
+                       changed = test_and_clear_bit(HCI_SC_ENABLED,
+                                                    &hdev->dev_flags);
+                       clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+               }
+
+               err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
+               if (err < 0)
+                       goto failed;
+
+               if (changed)
+                       err = new_settings(hdev, sk);
+
+               goto failed;
+       }
+
+       if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
+               err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
+                                MGMT_STATUS_BUSY);
+               goto failed;
+       }
+
+       val = !!cp->val;
+
+       if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
+           (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) {
+               err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
+               goto failed;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto failed;
+       }
+
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
+       if (err < 0) {
+               mgmt_pending_remove(cmd);
+               goto failed;
+       }
+
+       if (cp->val == 0x02)
+               set_bit(HCI_SC_ONLY, &hdev->dev_flags);
+       else
+               clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+
+failed:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
+                         void *data, u16 len)
+{
+       struct mgmt_mode *cp = data;
+       bool changed;
+       int err;
+
+       BT_DBG("request for %s", hdev->name);
+
+       if (cp->val != 0x00 && cp->val != 0x01)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
+                                 MGMT_STATUS_INVALID_PARAMS);
+
+       hci_dev_lock(hdev);
+
+       if (cp->val)
+               changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+       else
+               changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+
+       err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
+       if (err < 0)
+               goto unlock;
+
+       if (changed)
+               err = new_settings(hdev, sk);
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
+                      u16 len)
+{
+       struct mgmt_cp_set_privacy *cp = cp_data;
+       bool changed;
+       int err;
+
+       BT_DBG("request for %s", hdev->name);
+
+       if (!lmp_le_capable(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
+       if (cp->privacy != 0x00 && cp->privacy != 0x01)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
+                                 MGMT_STATUS_INVALID_PARAMS);
+
+       if (hdev_is_powered(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
+                                 MGMT_STATUS_REJECTED);
+
+       hci_dev_lock(hdev);
+
+       /* If user space supports this command it is also expected to
+        * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
+        */
+       set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
+
+       if (cp->privacy) {
+               changed = !test_and_set_bit(HCI_PRIVACY, &hdev->dev_flags);
+               memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
+               set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
+       } else {
+               changed = test_and_clear_bit(HCI_PRIVACY, &hdev->dev_flags);
+               memset(hdev->irk, 0, sizeof(hdev->irk));
+               clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
+       }
+
+       err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
+       if (err < 0)
+               goto unlock;
+
+       if (changed)
+               err = new_settings(hdev, sk);
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static bool irk_is_valid(struct mgmt_irk_info *irk)
+{
+       switch (irk->addr.type) {
+       case BDADDR_LE_PUBLIC:
+               return true;
+
+       case BDADDR_LE_RANDOM:
+               /* Two most significant bits shall be set */
+               if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
+                       return false;
+               return true;
+       }
+
+       return false;
+}
+
+static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
+                    u16 len)
+{
+       struct mgmt_cp_load_irks *cp = cp_data;
+       u16 irk_count, expected_len;
+       int i, err;
+
+       BT_DBG("request for %s", hdev->name);
+
+       if (!lmp_le_capable(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
+       irk_count = __le16_to_cpu(cp->irk_count);
+
+       expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
+       if (expected_len != len) {
+               BT_ERR("load_irks: expected %u bytes, got %u bytes",
+                      len, expected_len);
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
+                                 MGMT_STATUS_INVALID_PARAMS);
+       }
+
+       BT_DBG("%s irk_count %u", hdev->name, irk_count);
+
+       for (i = 0; i < irk_count; i++) {
+               struct mgmt_irk_info *key = &cp->irks[i];
+
+               if (!irk_is_valid(key))
+                       return cmd_status(sk, hdev->id,
+                                         MGMT_OP_LOAD_IRKS,
+                                         MGMT_STATUS_INVALID_PARAMS);
+       }
+
+       hci_dev_lock(hdev);
+
+       hci_smp_irks_clear(hdev);
+
+       for (i = 0; i < irk_count; i++) {
+               struct mgmt_irk_info *irk = &cp->irks[i];
+               u8 addr_type;
+
+               if (irk->addr.type == BDADDR_LE_PUBLIC)
+                       addr_type = ADDR_LE_DEV_PUBLIC;
+               else
+                       addr_type = ADDR_LE_DEV_RANDOM;
+
+               hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
+                           BDADDR_ANY);
+       }
+
+       set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
+
+       err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
+
+       hci_dev_unlock(hdev);
+
+       return err;
+}
+
 static bool ltk_is_valid(struct mgmt_ltk_info *key)
 {
-       if (key->authenticated != 0x00 && key->authenticated != 0x01)
-               return false;
        if (key->master != 0x00 && key->master != 0x01)
                return false;
-       if (!bdaddr_type_is_le(key->addr.type))
-               return false;
-       return true;
+
+       switch (key->addr.type) {
+       case BDADDR_LE_PUBLIC:
+               return true;
+
+       case BDADDR_LE_RANDOM:
+               /* Two most significant bits shall be set */
+               if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
+                       return false;
+               return true;
+       }
+
+       return false;
 }
 
 static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
@@ -4063,9 +4541,9 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
                else
                        type = HCI_SMP_LTK_SLAVE;
 
-               hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
-                           type, 0, key->authenticated, key->val,
-                           key->enc_size, key->ediv, key->rand);
+               hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
+                           key->type, key->val, key->enc_size, key->ediv,
+                           key->rand);
        }
 
        err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
@@ -4115,7 +4593,7 @@ static const struct mgmt_handler {
        { user_passkey_reply,     false, MGMT_USER_PASSKEY_REPLY_SIZE },
        { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
        { read_local_oob_data,    false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
-       { add_remote_oob_data,    false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
+       { add_remote_oob_data,    true,  MGMT_ADD_REMOTE_OOB_DATA_SIZE },
        { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
        { start_discovery,        false, MGMT_START_DISCOVERY_SIZE },
        { stop_discovery,         false, MGMT_STOP_DISCOVERY_SIZE },
@@ -4127,6 +4605,10 @@ static const struct mgmt_handler {
        { set_bredr,              false, MGMT_SETTING_SIZE },
        { set_static_address,     false, MGMT_SET_STATIC_ADDRESS_SIZE },
        { set_scan_params,        false, MGMT_SET_SCAN_PARAMS_SIZE },
+       { set_secure_conn,        false, MGMT_SETTING_SIZE },
+       { set_debug_keys,         false, MGMT_SETTING_SIZE },
+       { set_privacy,            false, MGMT_SET_PRIVACY_SIZE },
+       { load_irks,              true,  MGMT_LOAD_IRKS_SIZE },
 };
 
 
@@ -4243,6 +4725,17 @@ void mgmt_index_removed(struct hci_dev *hdev)
        mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
 }
 
+/* This function requires the caller holds hdev->lock */
+static void restart_le_auto_conns(struct hci_dev *hdev)
+{
+       struct hci_conn_params *p;
+
+       list_for_each_entry(p, &hdev->le_conn_params, list) {
+               if (p->auto_connect == HCI_AUTO_CONN_ALWAYS)
+                       hci_pend_le_conn_add(hdev, &p->addr, p->addr_type);
+       }
+}
+
 static void powered_complete(struct hci_dev *hdev, u8 status)
 {
        struct cmd_lookup match = { NULL, hdev };
@@ -4251,6 +4744,8 @@ static void powered_complete(struct hci_dev *hdev, u8 status)
 
        hci_dev_lock(hdev);
 
+       restart_le_auto_conns(hdev);
+
        mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
 
        new_settings(hdev, match.sk);
@@ -4292,11 +4787,6 @@ static int powered_update_hci(struct hci_dev *hdev)
        }
 
        if (lmp_le_capable(hdev)) {
-               /* Set random address to static address if configured */
-               if (bacmp(&hdev->static_addr, BDADDR_ANY))
-                       hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
-                                   &hdev->static_addr);
-
                /* Make sure the controller has a good default for
                 * advertising data. This also applies to the case
                 * where BR/EDR was toggled during the AUTO_OFF phase.
@@ -4422,6 +4912,10 @@ void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
        if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
                return;
 
+       /* Powering off may clear the scan mode - don't let that interfere */
+       if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
+               return;
+
        if (discoverable) {
                changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
        } else {
@@ -4455,6 +4949,10 @@ void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
        if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
                return;
 
+       /* Powering off may clear the scan mode - don't let that interfere */
+       if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
+               return;
+
        if (connectable)
                changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
        else
@@ -4464,6 +4962,18 @@ void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
                new_settings(hdev, NULL);
 }
 
+void mgmt_advertising(struct hci_dev *hdev, u8 advertising)
+{
+       /* Powering off may stop advertising - don't let that interfere */
+       if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
+               return;
+
+       if (advertising)
+               set_bit(HCI_ADVERTISING, &hdev->dev_flags);
+       else
+               clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
+}
+
 void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
 {
        u8 mgmt_err = mgmt_status(status);
@@ -4494,28 +5004,74 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
        mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
 }
 
-void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
+void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key)
 {
        struct mgmt_ev_new_long_term_key ev;
 
        memset(&ev, 0, sizeof(ev));
 
-       ev.store_hint = persistent;
+       /* Devices using resolvable or non-resolvable random addresses
+        * without providing an indentity resolving key don't require
+        * to store long term keys. Their addresses will change the
+        * next time around.
+        *
+        * Only when a remote device provides an identity address
+        * make sure the long term key is stored. If the remote
+        * identity is known, the long term keys are internally
+        * mapped to the identity address. So allow static random
+        * and public addresses here.
+        */
+       if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
+           (key->bdaddr.b[5] & 0xc0) != 0xc0)
+               ev.store_hint = 0x00;
+       else
+               ev.store_hint = 0x01;
+
        bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
        ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
-       ev.key.authenticated = key->authenticated;
+       ev.key.type = key->authenticated;
        ev.key.enc_size = key->enc_size;
        ev.key.ediv = key->ediv;
+       ev.key.rand = key->rand;
 
        if (key->type == HCI_SMP_LTK)
                ev.key.master = 1;
 
-       memcpy(ev.key.rand, key->rand, sizeof(key->rand));
        memcpy(ev.key.val, key->val, sizeof(key->val));
 
        mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
 }
 
+void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
+{
+       struct mgmt_ev_new_irk ev;
+
+       memset(&ev, 0, sizeof(ev));
+
+       /* For identity resolving keys from devices that are already
+        * using a public address or static random address, do not
+        * ask for storing this key. The identity resolving key really
+        * is only mandatory for devices using resovlable random
+        * addresses.
+        *
+        * Storing all identity resolving keys has the downside that
+        * they will be also loaded on next boot of they system. More
+        * identity resolving keys, means more time during scanning is
+        * needed to actually resolve these addresses.
+        */
+       if (bacmp(&irk->rpa, BDADDR_ANY))
+               ev.store_hint = 0x01;
+       else
+               ev.store_hint = 0x00;
+
+       bacpy(&ev.rpa, &irk->rpa);
+       bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
+       ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
+       memcpy(ev.irk.val, irk->val, sizeof(irk->val));
+
+       mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
+}
+
 static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
                                  u8 data_len)
 {
@@ -4590,11 +5146,29 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
 }
 
 void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                             u8 link_type, u8 addr_type, u8 reason)
+                             u8 link_type, u8 addr_type, u8 reason,
+                             bool mgmt_connected)
 {
        struct mgmt_ev_device_disconnected ev;
+       struct pending_cmd *power_off;
        struct sock *sk = NULL;
 
+       power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
+       if (power_off) {
+               struct mgmt_mode *cp = power_off->param;
+
+               /* The connection is still in hci_conn_hash so test for 1
+                * instead of 0 to know if this is the last one.
+                */
+               if (!cp->val && hci_conn_count(hdev) == 1) {
+                       cancel_delayed_work(&hdev->power_off);
+                       queue_work(hdev->req_workqueue, &hdev->power_off.work);
+               }
+       }
+
+       if (!mgmt_connected)
+               return;
+
        if (link_type != ACL_LINK && link_type != LE_LINK)
                return;
 
@@ -4649,6 +5223,20 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                         u8 addr_type, u8 status)
 {
        struct mgmt_ev_connect_failed ev;
+       struct pending_cmd *power_off;
+
+       power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
+       if (power_off) {
+               struct mgmt_mode *cp = power_off->param;
+
+               /* The connection is still in hci_conn_hash so test for 1
+                * instead of 0 to know if this is the last one.
+                */
+               if (!cp->val && hci_conn_count(hdev) == 1) {
+                       cancel_delayed_work(&hdev->power_off);
+                       queue_work(hdev->req_workqueue, &hdev->power_off.work);
+               }
+       }
 
        bacpy(&ev.addr.bdaddr, bdaddr);
        ev.addr.type = link_to_bdaddr(link_type, addr_type);
@@ -4910,6 +5498,43 @@ void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
        hci_req_run(&req, NULL);
 }
 
+void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
+{
+       struct cmd_lookup match = { NULL, hdev };
+       bool changed = false;
+
+       if (status) {
+               u8 mgmt_err = mgmt_status(status);
+
+               if (enable) {
+                       if (test_and_clear_bit(HCI_SC_ENABLED,
+                                              &hdev->dev_flags))
+                               new_settings(hdev, NULL);
+                       clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+               }
+
+               mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
+                                    cmd_status_rsp, &mgmt_err);
+               return;
+       }
+
+       if (enable) {
+               changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
+       } else {
+               changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
+               clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+       }
+
+       mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
+                            settings_rsp, &match);
+
+       if (changed)
+               new_settings(hdev, match.sk);
+
+       if (match.sk)
+               sock_put(match.sk);
+}
+
 static void sk_lookup(struct pending_cmd *cmd, void *data)
 {
        struct cmd_lookup *match = data;
@@ -4964,8 +5589,9 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
                   cmd ? cmd->sk : NULL);
 }
 
-void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
-                                            u8 *randomizer, u8 status)
+void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
+                                      u8 *randomizer192, u8 *hash256,
+                                      u8 *randomizer256, u8 status)
 {
        struct pending_cmd *cmd;
 
@@ -4979,13 +5605,32 @@ void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
                cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
                           mgmt_status(status));
        } else {
-               struct mgmt_rp_read_local_oob_data rp;
+               if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
+                   hash256 && randomizer256) {
+                       struct mgmt_rp_read_local_oob_ext_data rp;
+
+                       memcpy(rp.hash192, hash192, sizeof(rp.hash192));
+                       memcpy(rp.randomizer192, randomizer192,
+                              sizeof(rp.randomizer192));
+
+                       memcpy(rp.hash256, hash256, sizeof(rp.hash256));
+                       memcpy(rp.randomizer256, randomizer256,
+                              sizeof(rp.randomizer256));
+
+                       cmd_complete(cmd->sk, hdev->id,
+                                    MGMT_OP_READ_LOCAL_OOB_DATA, 0,
+                                    &rp, sizeof(rp));
+               } else {
+                       struct mgmt_rp_read_local_oob_data rp;
 
-               memcpy(rp.hash, hash, sizeof(rp.hash));
-               memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
+                       memcpy(rp.hash, hash192, sizeof(rp.hash));
+                       memcpy(rp.randomizer, randomizer192,
+                              sizeof(rp.randomizer));
 
-               cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
-                            0, &rp, sizeof(rp));
+                       cmd_complete(cmd->sk, hdev->id,
+                                    MGMT_OP_READ_LOCAL_OOB_DATA, 0,
+                                    &rp, sizeof(rp));
+               }
        }
 
        mgmt_pending_remove(cmd);
@@ -4997,6 +5642,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 {
        char buf[512];
        struct mgmt_ev_device_found *ev = (void *) buf;
+       struct smp_irk *irk;
        size_t ev_size;
 
        if (!hci_discovery_active(hdev))
@@ -5008,8 +5654,15 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 
        memset(buf, 0, sizeof(buf));
 
-       bacpy(&ev->addr.bdaddr, bdaddr);
-       ev->addr.type = link_to_bdaddr(link_type, addr_type);
+       irk = hci_get_irk(hdev, bdaddr, addr_type);
+       if (irk) {
+               bacpy(&ev->addr.bdaddr, &irk->bdaddr);
+               ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
+       } else {
+               bacpy(&ev->addr.bdaddr, bdaddr);
+               ev->addr.type = link_to_bdaddr(link_type, addr_type);
+       }
+
        ev->rssi = rssi;
        if (cfm_name)
                ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
index facd8a79c0383eb8898fca8dc905c87ed623202a..21e15318937c31e8d7b6c8f286036dfa2ec22300 100644 (file)
@@ -216,6 +216,7 @@ static int rfcomm_check_security(struct rfcomm_dlc *d)
 
        switch (d->sec_level) {
        case BT_SECURITY_HIGH:
+       case BT_SECURITY_FIPS:
                auth_type = HCI_AT_GENERAL_BONDING_MITM;
                break;
        case BT_SECURITY_MEDIUM:
@@ -359,6 +360,11 @@ static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
        return NULL;
 }
 
+static int rfcomm_check_channel(u8 channel)
+{
+       return channel < 1 || channel > 30;
+}
+
 static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
 {
        struct rfcomm_session *s;
@@ -368,7 +374,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
        BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d",
               d, d->state, src, dst, channel);
 
-       if (channel < 1 || channel > 30)
+       if (rfcomm_check_channel(channel))
                return -EINVAL;
 
        if (d->state != BT_OPEN && d->state != BT_CLOSED)
@@ -425,6 +431,20 @@ int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 chann
        return r;
 }
 
+static void __rfcomm_dlc_disconn(struct rfcomm_dlc *d)
+{
+       struct rfcomm_session *s = d->session;
+
+       d->state = BT_DISCONN;
+       if (skb_queue_empty(&d->tx_queue)) {
+               rfcomm_send_disc(s, d->dlci);
+               rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
+       } else {
+               rfcomm_queue_disc(d);
+               rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
+       }
+}
+
 static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
 {
        struct rfcomm_session *s = d->session;
@@ -437,32 +457,29 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
        switch (d->state) {
        case BT_CONNECT:
        case BT_CONFIG:
+       case BT_OPEN:
+       case BT_CONNECT2:
                if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
                        set_bit(RFCOMM_AUTH_REJECT, &d->flags);
                        rfcomm_schedule();
-                       break;
+                       return 0;
                }
-               /* Fall through */
+       }
 
+       switch (d->state) {
+       case BT_CONNECT:
        case BT_CONNECTED:
-               d->state = BT_DISCONN;
-               if (skb_queue_empty(&d->tx_queue)) {
-                       rfcomm_send_disc(s, d->dlci);
-                       rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
-               } else {
-                       rfcomm_queue_disc(d);
-                       rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
-               }
+               __rfcomm_dlc_disconn(d);
                break;
 
-       case BT_OPEN:
-       case BT_CONNECT2:
-               if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
-                       set_bit(RFCOMM_AUTH_REJECT, &d->flags);
-                       rfcomm_schedule();
+       case BT_CONFIG:
+               if (s->state != BT_BOUND) {
+                       __rfcomm_dlc_disconn(d);
                        break;
                }
-               /* Fall through */
+               /* if closing a dlc in a session that hasn't been started,
+                * just close and unlink the dlc
+                */
 
        default:
                rfcomm_dlc_clear_timer(d);
@@ -513,6 +530,25 @@ no_session:
        return r;
 }
 
+struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel)
+{
+       struct rfcomm_session *s;
+       struct rfcomm_dlc *dlc = NULL;
+       u8 dlci;
+
+       if (rfcomm_check_channel(channel))
+               return ERR_PTR(-EINVAL);
+
+       rfcomm_lock();
+       s = rfcomm_session_get(src, dst);
+       if (s) {
+               dlci = __dlci(!s->initiator, channel);
+               dlc = rfcomm_dlc_get(s, dlci);
+       }
+       rfcomm_unlock();
+       return dlc;
+}
+
 int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
 {
        int len = skb->len;
@@ -533,6 +569,20 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
        return len;
 }
 
+void rfcomm_dlc_send_noerror(struct rfcomm_dlc *d, struct sk_buff *skb)
+{
+       int len = skb->len;
+
+       BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
+
+       rfcomm_make_uih(skb, d->addr);
+       skb_queue_tail(&d->tx_queue, skb);
+
+       if (d->state == BT_CONNECTED &&
+           !test_bit(RFCOMM_TX_THROTTLED, &d->flags))
+               rfcomm_schedule();
+}
+
 void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
 {
        BT_DBG("dlc %p state %ld", d, d->state);
@@ -1943,12 +1993,11 @@ static void rfcomm_process_sessions(void)
                        continue;
                }
 
-               if (s->state == BT_LISTEN) {
+               switch (s->state) {
+               case BT_LISTEN:
                        rfcomm_accept_connection(s);
                        continue;
-               }
 
-               switch (s->state) {
                case BT_BOUND:
                        s = rfcomm_check_connection(s);
                        break;
@@ -2085,7 +2134,8 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
                                set_bit(RFCOMM_SEC_PENDING, &d->flags);
                                rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
                                continue;
-                       } else if (d->sec_level == BT_SECURITY_HIGH) {
+                       } else if (d->sec_level == BT_SECURITY_HIGH ||
+                                  d->sec_level == BT_SECURITY_FIPS) {
                                set_bit(RFCOMM_ENC_DROP, &d->flags);
                                continue;
                        }
index 3c2d3e4aa2f58a271bea6632451edd21b92668a9..c024e715512fdff242616c4ac403fa8315b13289 100644 (file)
@@ -105,13 +105,18 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
 }
 
 /* ---- Socket functions ---- */
-static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
+static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src)
 {
        struct sock *sk = NULL;
 
        sk_for_each(sk, &rfcomm_sk_list.head) {
-               if (rfcomm_pi(sk)->channel == channel &&
-                               !bacmp(&rfcomm_pi(sk)->src, src))
+               if (rfcomm_pi(sk)->channel != channel)
+                       continue;
+
+               if (bacmp(&rfcomm_pi(sk)->src, src))
+                       continue;
+
+               if (sk->sk_state == BT_BOUND || sk->sk_state == BT_LISTEN)
                        break;
        }
 
@@ -331,6 +336,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
 {
        struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
        struct sock *sk = sock->sk;
+       int chan = sa->rc_channel;
        int err = 0;
 
        BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
@@ -352,12 +358,12 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
 
        write_lock(&rfcomm_sk_list.lock);
 
-       if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
+       if (chan && __rfcomm_get_listen_sock_by_addr(chan, &sa->rc_bdaddr)) {
                err = -EADDRINUSE;
        } else {
                /* Save source address */
                bacpy(&rfcomm_pi(sk)->src, &sa->rc_bdaddr);
-               rfcomm_pi(sk)->channel = sa->rc_channel;
+               rfcomm_pi(sk)->channel = chan;
                sk->sk_state = BT_BOUND;
        }
 
@@ -439,7 +445,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog)
                write_lock(&rfcomm_sk_list.lock);
 
                for (channel = 1; channel < 31; channel++)
-                       if (!__rfcomm_get_sock_by_addr(channel, src)) {
+                       if (!__rfcomm_get_listen_sock_by_addr(channel, src)) {
                                rfcomm_pi(sk)->channel = channel;
                                err = 0;
                                break;
@@ -528,6 +534,9 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
+       if (peer && sk->sk_state != BT_CONNECTED)
+               return -ENOTCONN;
+
        memset(sa, 0, sizeof(*sa));
        sa->rc_family  = AF_BLUETOOTH;
        sa->rc_channel = rfcomm_pi(sk)->channel;
@@ -648,6 +657,11 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
                        break;
                }
 
+               if (opt & RFCOMM_LM_FIPS) {
+                       err = -EINVAL;
+                       break;
+               }
+
                if (opt & RFCOMM_LM_AUTH)
                        rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
                if (opt & RFCOMM_LM_ENCRYPT)
@@ -762,7 +776,11 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
                        break;
                case BT_SECURITY_HIGH:
                        opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
-                                                       RFCOMM_LM_SECURE;
+                             RFCOMM_LM_SECURE;
+                       break;
+               case BT_SECURITY_FIPS:
+                       opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
+                             RFCOMM_LM_SECURE | RFCOMM_LM_FIPS;
                        break;
                default:
                        opt = 0;
@@ -774,6 +792,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 
                if (put_user(opt, (u32 __user *) optval))
                        err = -EFAULT;
+
                break;
 
        case RFCOMM_CONNINFO:
index f9c0980abeeac9eaf1d94d70f3e001fd6e1f0870..403ec09f480a2a72983b0b1b9db0222fd6e86742 100644 (file)
@@ -40,6 +40,7 @@
 #define RFCOMM_TTY_MAJOR 216           /* device node major id of the usb/bluetooth.c driver */
 #define RFCOMM_TTY_MINOR 0
 
+static DEFINE_MUTEX(rfcomm_ioctl_mutex);
 static struct tty_driver *rfcomm_tty_driver;
 
 struct rfcomm_dev {
@@ -51,6 +52,8 @@ struct rfcomm_dev {
        unsigned long           flags;
        int                     err;
 
+       unsigned long           status;         /* don't export to userspace */
+
        bdaddr_t                src;
        bdaddr_t                dst;
        u8                      channel;
@@ -58,7 +61,6 @@ struct rfcomm_dev {
        uint                    modem_status;
 
        struct rfcomm_dlc       *dlc;
-       wait_queue_head_t       conn_wait;
 
        struct device           *tty_dev;
 
@@ -83,10 +85,6 @@ static void rfcomm_dev_destruct(struct tty_port *port)
 
        BT_DBG("dev %p dlc %p", dev, dlc);
 
-       spin_lock(&rfcomm_dev_lock);
-       list_del(&dev->list);
-       spin_unlock(&rfcomm_dev_lock);
-
        rfcomm_dlc_lock(dlc);
        /* Detach DLC if it's owned by this dev */
        if (dlc->owner == dev)
@@ -95,7 +93,12 @@ static void rfcomm_dev_destruct(struct tty_port *port)
 
        rfcomm_dlc_put(dlc);
 
-       tty_unregister_device(rfcomm_tty_driver, dev->id);
+       if (dev->tty_dev)
+               tty_unregister_device(rfcomm_tty_driver, dev->id);
+
+       spin_lock(&rfcomm_dev_lock);
+       list_del(&dev->list);
+       spin_unlock(&rfcomm_dev_lock);
 
        kfree(dev);
 
@@ -104,60 +107,24 @@ static void rfcomm_dev_destruct(struct tty_port *port)
        module_put(THIS_MODULE);
 }
 
-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;
-}
-
 /* 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);
+               set_bit(TTY_IO_ERROR, &tty->flags);
+       return err;
+}
 
-       if (!err)
-               device_move(dev->tty_dev, rfcomm_get_device(dev),
-                           DPM_ORDER_DEV_AFTER_PARENT);
+/* we block the open until the dlc->state becomes BT_CONNECTED */
+static int rfcomm_dev_carrier_raised(struct tty_port *port)
+{
+       struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
 
-       return err;
+       return (dev->dlc->state == BT_CONNECTED);
 }
 
 /* device-specific cleanup: close the dlc */
@@ -176,9 +143,10 @@ 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)
+static struct rfcomm_dev *__rfcomm_dev_lookup(int id)
 {
        struct rfcomm_dev *dev;
 
@@ -195,20 +163,41 @@ static struct rfcomm_dev *rfcomm_dev_get(int id)
 
        spin_lock(&rfcomm_dev_lock);
 
-       dev = __rfcomm_dev_get(id);
+       dev = __rfcomm_dev_lookup(id);
 
-       if (dev) {
-               if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
-                       dev = NULL;
-               else
-                       tty_port_get(&dev->port);
-       }
+       if (dev && !tty_port_get(&dev->port))
+               dev = NULL;
 
        spin_unlock(&rfcomm_dev_lock);
 
        return dev;
 }
 
+static void rfcomm_reparent_device(struct rfcomm_dev *dev)
+{
+       struct hci_dev *hdev;
+       struct hci_conn *conn;
+
+       hdev = hci_get_route(&dev->dst, &dev->src);
+       if (!hdev)
+               return;
+
+       /* The lookup results are unsafe to access without the
+        * hci device lock (FIXME: why is this not documented?)
+        */
+       hci_dev_lock(hdev);
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
+
+       /* Just because the acl link is in the hash table is no
+        * guarantee the sysfs device has been added ...
+        */
+       if (conn && device_is_registered(&conn->dev))
+               device_move(dev->tty_dev, &conn->dev, DPM_ORDER_DEV_AFTER_PARENT);
+
+       hci_dev_unlock(hdev);
+       hci_dev_put(hdev);
+}
+
 static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
 {
        struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
@@ -224,17 +213,16 @@ static ssize_t show_channel(struct device *tty_dev, struct device_attribute *att
 static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
 static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
 
-static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
+static struct rfcomm_dev *__rfcomm_dev_add(struct rfcomm_dev_req *req,
+                                          struct rfcomm_dlc *dlc)
 {
        struct rfcomm_dev *dev, *entry;
        struct list_head *head = &rfcomm_dev_list;
        int err = 0;
 
-       BT_DBG("id %d channel %d", req->dev_id, req->channel);
-
        dev = kzalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
        if (!dev)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        spin_lock(&rfcomm_dev_lock);
 
@@ -282,7 +270,6 @@ 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);
 
@@ -318,22 +305,37 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
           holds reference to this module. */
        __module_get(THIS_MODULE);
 
+       spin_unlock(&rfcomm_dev_lock);
+       return dev;
+
 out:
        spin_unlock(&rfcomm_dev_lock);
+       kfree(dev);
+       return ERR_PTR(err);
+}
+
+static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
+{
+       struct rfcomm_dev *dev;
+       struct device *tty;
+
+       BT_DBG("id %d channel %d", req->dev_id, req->channel);
 
-       if (err < 0)
-               goto free;
+       dev = __rfcomm_dev_add(req, dlc);
+       if (IS_ERR(dev)) {
+               rfcomm_dlc_put(dlc);
+               return PTR_ERR(dev);
+       }
 
-       dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver,
+       tty = tty_port_register_device(&dev->port, rfcomm_tty_driver,
                        dev->id, NULL);
-       if (IS_ERR(dev->tty_dev)) {
-               err = PTR_ERR(dev->tty_dev);
-               spin_lock(&rfcomm_dev_lock);
-               list_del(&dev->list);
-               spin_unlock(&rfcomm_dev_lock);
-               goto free;
+       if (IS_ERR(tty)) {
+               tty_port_put(&dev->port);
+               return PTR_ERR(tty);
        }
 
+       dev->tty_dev = tty;
+       rfcomm_reparent_device(dev);
        dev_set_drvdata(dev->tty_dev, dev);
 
        if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
@@ -343,24 +345,23 @@ out:
                BT_ERR("Failed to create channel attribute");
 
        return dev->id;
-
-free:
-       kfree(dev);
-       return err;
 }
 
 /* ---- Send buffer ---- */
-static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
+static inline unsigned int rfcomm_room(struct rfcomm_dev *dev)
 {
-       /* We can't let it be zero, because we don't get a callback
-          when tx_credits becomes nonzero, hence we'd never wake up */
-       return dlc->mtu * (dlc->tx_credits?:1);
+       struct rfcomm_dlc *dlc = dev->dlc;
+
+       /* Limit the outstanding number of packets not yet sent to 40 */
+       int pending = 40 - atomic_read(&dev->wmem_alloc);
+
+       return max(0, pending) * dlc->mtu;
 }
 
 static void rfcomm_wfree(struct sk_buff *skb)
 {
        struct rfcomm_dev *dev = (void *) skb->sk;
-       atomic_sub(skb->truesize, &dev->wmem_alloc);
+       atomic_dec(&dev->wmem_alloc);
        if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
                tty_port_tty_wakeup(&dev->port);
        tty_port_put(&dev->port);
@@ -369,28 +370,24 @@ static void rfcomm_wfree(struct sk_buff *skb)
 static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
 {
        tty_port_get(&dev->port);
-       atomic_add(skb->truesize, &dev->wmem_alloc);
+       atomic_inc(&dev->wmem_alloc);
        skb->sk = (void *) dev;
        skb->destructor = rfcomm_wfree;
 }
 
 static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, gfp_t priority)
 {
-       if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
-               struct sk_buff *skb = alloc_skb(size, priority);
-               if (skb) {
-                       rfcomm_set_owner_w(skb, dev);
-                       return skb;
-               }
-       }
-       return NULL;
+       struct sk_buff *skb = alloc_skb(size, priority);
+       if (skb)
+               rfcomm_set_owner_w(skb, dev);
+       return skb;
 }
 
 /* ---- Device IOCTLs ---- */
 
 #define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
 
-static int rfcomm_create_dev(struct sock *sk, void __user *arg)
+static int __rfcomm_create_dev(struct sock *sk, void __user *arg)
 {
        struct rfcomm_dev_req req;
        struct rfcomm_dlc *dlc;
@@ -412,16 +409,22 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg)
                dlc = rfcomm_pi(sk)->dlc;
                rfcomm_dlc_hold(dlc);
        } else {
+               /* Validate the channel is unused */
+               dlc = rfcomm_dlc_exists(&req.src, &req.dst, req.channel);
+               if (IS_ERR(dlc))
+                       return PTR_ERR(dlc);
+               else if (dlc) {
+                       rfcomm_dlc_put(dlc);
+                       return -EBUSY;
+               }
                dlc = rfcomm_dlc_alloc(GFP_KERNEL);
                if (!dlc)
                        return -ENOMEM;
        }
 
        id = rfcomm_dev_add(&req, dlc);
-       if (id < 0) {
-               rfcomm_dlc_put(dlc);
+       if (id < 0)
                return id;
-       }
 
        if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
                /* DLC is now used by device.
@@ -432,7 +435,7 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg)
        return id;
 }
 
-static int rfcomm_release_dev(void __user *arg)
+static int __rfcomm_release_dev(void __user *arg)
 {
        struct rfcomm_dev_req req;
        struct rfcomm_dev *dev;
@@ -452,6 +455,12 @@ static int rfcomm_release_dev(void __user *arg)
                return -EPERM;
        }
 
+       /* only release once */
+       if (test_and_set_bit(RFCOMM_DEV_RELEASED, &dev->status)) {
+               tty_port_put(&dev->port);
+               return -EALREADY;
+       }
+
        if (req.flags & (1 << RFCOMM_HANGUP_NOW))
                rfcomm_dlc_close(dev->dlc, 0);
 
@@ -462,14 +471,35 @@ static int rfcomm_release_dev(void __user *arg)
                tty_kref_put(tty);
        }
 
-       if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
-           !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+       if (!test_bit(RFCOMM_TTY_OWNED, &dev->status))
                tty_port_put(&dev->port);
 
        tty_port_put(&dev->port);
        return 0;
 }
 
+static int rfcomm_create_dev(struct sock *sk, void __user *arg)
+{
+       int ret;
+
+       mutex_lock(&rfcomm_ioctl_mutex);
+       ret = __rfcomm_create_dev(sk, arg);
+       mutex_unlock(&rfcomm_ioctl_mutex);
+
+       return ret;
+}
+
+static int rfcomm_release_dev(void __user *arg)
+{
+       int ret;
+
+       mutex_lock(&rfcomm_ioctl_mutex);
+       ret = __rfcomm_release_dev(arg);
+       mutex_unlock(&rfcomm_ioctl_mutex);
+
+       return ret;
+}
+
 static int rfcomm_get_dev_list(void __user *arg)
 {
        struct rfcomm_dev *dev;
@@ -497,7 +527,7 @@ static int rfcomm_get_dev_list(void __user *arg)
        spin_lock(&rfcomm_dev_lock);
 
        list_for_each_entry(dev, &rfcomm_dev_list, list) {
-               if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+               if (!tty_port_get(&dev->port))
                        continue;
                (di + n)->id      = dev->id;
                (di + n)->flags   = dev->flags;
@@ -505,6 +535,7 @@ static int rfcomm_get_dev_list(void __user *arg)
                (di + n)->channel = dev->channel;
                bacpy(&(di + n)->src, &dev->src);
                bacpy(&(di + n)->dst, &dev->dst);
+               tty_port_put(&dev->port);
                if (++n >= dev_num)
                        break;
        }
@@ -601,9 +632,11 @@ 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;
-       wake_up_interruptible(&dev->conn_wait);
+       if (dlc->state == BT_CONNECTED) {
+               rfcomm_reparent_device(dev);
 
-       if (dlc->state == BT_CLOSED)
+               wake_up_interruptible(&dev->port.open_wait);
+       } else if (dlc->state == BT_CLOSED)
                tty_port_tty_hangup(&dev->port, false);
 }
 
@@ -703,8 +736,10 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
         * when the last process closes the tty. The behaviour is expected by
         * userspace.
         */
-       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
+               set_bit(RFCOMM_TTY_OWNED, &dev->status);
                tty_port_put(&dev->port);
+       }
 
        return 0;
 }
@@ -750,7 +785,7 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in
        struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
        struct rfcomm_dlc *dlc = dev->dlc;
        struct sk_buff *skb;
-       int err = 0, sent = 0, size;
+       int sent = 0, size;
 
        BT_DBG("tty %p count %d", tty, count);
 
@@ -758,7 +793,6 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in
                size = min_t(uint, count, dlc->mtu);
 
                skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
-
                if (!skb)
                        break;
 
@@ -766,32 +800,24 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in
 
                memcpy(skb_put(skb, size), buf + sent, size);
 
-               err = rfcomm_dlc_send(dlc, skb);
-               if (err < 0) {
-                       kfree_skb(skb);
-                       break;
-               }
+               rfcomm_dlc_send_noerror(dlc, skb);
 
                sent  += size;
                count -= size;
        }
 
-       return sent ? sent : err;
+       return sent;
 }
 
 static int rfcomm_tty_write_room(struct tty_struct *tty)
 {
        struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-       int room;
+       int room = 0;
 
-       BT_DBG("tty %p", tty);
-
-       if (!dev || !dev->dlc)
-               return 0;
+       if (dev && dev->dlc)
+               room = rfcomm_room(dev);
 
-       room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
-       if (room < 0)
-               room = 0;
+       BT_DBG("tty %p room %d", tty, room);
 
        return room;
 }
@@ -1125,7 +1151,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 | CLOCAL;
+       rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
        rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
        tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
 
index 45007362683b4e4cdfcf8131d79ff38aa95f5733..f886bcae1b7ea8c453495c051f96b668d2e08cb6 100644 (file)
@@ -78,6 +78,70 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
        return err;
 }
 
+static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
+{
+       u8 _res[16], k[16];
+       int err;
+
+       /* r' = padding || r */
+       memset(_res, 0, 13);
+       _res[13] = r[2];
+       _res[14] = r[1];
+       _res[15] = r[0];
+
+       swap128(irk, k);
+       err = smp_e(tfm, k, _res);
+       if (err) {
+               BT_ERR("Encrypt error");
+               return err;
+       }
+
+       /* The output of the random address function ah is:
+        *      ah(h, r) = e(k, r') mod 2^24
+        * The output of the security function e is then truncated to 24 bits
+        * by taking the least significant 24 bits of the output of e as the
+        * result of ah.
+        */
+       res[0] = _res[15];
+       res[1] = _res[14];
+       res[2] = _res[13];
+
+       return 0;
+}
+
+bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
+                    bdaddr_t *bdaddr)
+{
+       u8 hash[3];
+       int err;
+
+       BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk);
+
+       err = smp_ah(tfm, irk, &bdaddr->b[3], hash);
+       if (err)
+               return false;
+
+       return !memcmp(bdaddr->b, hash, 3);
+}
+
+int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa)
+{
+       int err;
+
+       get_random_bytes(&rpa->b[3], 3);
+
+       rpa->b[5] &= 0x3f;      /* Clear two most significant bits */
+       rpa->b[5] |= 0x40;      /* Set second most significant bit */
+
+       err = smp_ah(tfm, irk, &rpa->b[3], rpa->b);
+       if (err < 0)
+               return err;
+
+       BT_DBG("RPA %pMR", rpa);
+
+       return 0;
+}
+
 static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
                  u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
                  u8 _rat, bdaddr_t *ra, u8 res[16])
@@ -203,31 +267,45 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
                              struct smp_cmd_pairing *req,
                              struct smp_cmd_pairing *rsp, __u8 authreq)
 {
-       u8 dist_keys = 0;
+       struct smp_chan *smp = conn->smp_chan;
+       struct hci_conn *hcon = conn->hcon;
+       struct hci_dev *hdev = hcon->hdev;
+       u8 local_dist = 0, remote_dist = 0;
 
        if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
-               dist_keys = SMP_DIST_ENC_KEY;
+               local_dist = SMP_DIST_ENC_KEY;
+               remote_dist = SMP_DIST_ENC_KEY;
                authreq |= SMP_AUTH_BONDING;
        } else {
                authreq &= ~SMP_AUTH_BONDING;
        }
 
+       if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags))
+               remote_dist |= SMP_DIST_ID_KEY;
+
+       if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
+               local_dist |= SMP_DIST_ID_KEY;
+
        if (rsp == NULL) {
                req->io_capability = conn->hcon->io_capability;
                req->oob_flag = SMP_OOB_NOT_PRESENT;
                req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
-               req->init_key_dist = 0;
-               req->resp_key_dist = dist_keys;
+               req->init_key_dist = local_dist;
+               req->resp_key_dist = remote_dist;
                req->auth_req = (authreq & AUTH_REQ_MASK);
+
+               smp->remote_key_dist = remote_dist;
                return;
        }
 
        rsp->io_capability = conn->hcon->io_capability;
        rsp->oob_flag = SMP_OOB_NOT_PRESENT;
        rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
-       rsp->init_key_dist = 0;
-       rsp->resp_key_dist = req->resp_key_dist & dist_keys;
+       rsp->init_key_dist = req->init_key_dist & remote_dist;
+       rsp->resp_key_dist = req->resp_key_dist & local_dist;
        rsp->auth_req = (authreq & AUTH_REQ_MASK);
+
+       smp->remote_key_dist = rsp->init_key_dist;
 }
 
 static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
@@ -356,29 +434,23 @@ static void confirm_work(struct work_struct *work)
 {
        struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
        struct l2cap_conn *conn = smp->conn;
-       struct crypto_blkcipher *tfm;
+       struct hci_dev *hdev = conn->hcon->hdev;
+       struct crypto_blkcipher *tfm = hdev->tfm_aes;
        struct smp_cmd_pairing_confirm cp;
        int ret;
        u8 res[16], reason;
 
        BT_DBG("conn %p", conn);
 
-       tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(tfm)) {
-               reason = SMP_UNSPECIFIED;
-               goto error;
-       }
+       /* Prevent mutual access to hdev->tfm_aes */
+       hci_dev_lock(hdev);
 
-       smp->tfm = tfm;
+       ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
+                    conn->hcon->init_addr_type, &conn->hcon->init_addr,
+                    conn->hcon->resp_addr_type, &conn->hcon->resp_addr, res);
+
+       hci_dev_unlock(hdev);
 
-       if (conn->hcon->out)
-               ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
-                            conn->hcon->src_type, &conn->hcon->src,
-                            conn->hcon->dst_type, &conn->hcon->dst, res);
-       else
-               ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
-                            conn->hcon->dst_type, &conn->hcon->dst,
-                            conn->hcon->src_type, &conn->hcon->src, res);
        if (ret) {
                reason = SMP_UNSPECIFIED;
                goto error;
@@ -400,7 +472,8 @@ static void random_work(struct work_struct *work)
        struct smp_chan *smp = container_of(work, struct smp_chan, random);
        struct l2cap_conn *conn = smp->conn;
        struct hci_conn *hcon = conn->hcon;
-       struct crypto_blkcipher *tfm = smp->tfm;
+       struct hci_dev *hdev = hcon->hdev;
+       struct crypto_blkcipher *tfm = hdev->tfm_aes;
        u8 reason, confirm[16], res[16], key[16];
        int ret;
 
@@ -411,14 +484,15 @@ static void random_work(struct work_struct *work)
 
        BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
 
-       if (hcon->out)
-               ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
-                            hcon->src_type, &hcon->src,
-                            hcon->dst_type, &hcon->dst, res);
-       else
-               ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
-                            hcon->dst_type, &hcon->dst,
-                            hcon->src_type, &hcon->src, res);
+       /* Prevent mutual access to hdev->tfm_aes */
+       hci_dev_lock(hdev);
+
+       ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
+                    hcon->init_addr_type, &hcon->init_addr,
+                    hcon->resp_addr_type, &hcon->resp_addr, res);
+
+       hci_dev_unlock(hdev);
+
        if (ret) {
                reason = SMP_UNSPECIFIED;
                goto error;
@@ -433,11 +507,9 @@ static void random_work(struct work_struct *work)
        }
 
        if (hcon->out) {
-               u8 stk[16], rand[8];
-               __le16 ediv;
-
-               memset(rand, 0, sizeof(rand));
-               ediv = 0;
+               u8 stk[16];
+               __le64 rand = 0;
+               __le16 ediv = 0;
 
                smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
                swap128(key, stk);
@@ -453,11 +525,9 @@ static void random_work(struct work_struct *work)
                hci_le_start_enc(hcon, ediv, rand, stk);
                hcon->enc_key_size = smp->enc_key_size;
        } else {
-               u8 stk[16], r[16], rand[8];
-               __le16 ediv;
-
-               memset(rand, 0, sizeof(rand));
-               ediv = 0;
+               u8 stk[16], r[16];
+               __le64 rand = 0;
+               __le16 ediv = 0;
 
                swap128(smp->prnd, r);
                smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
@@ -469,7 +539,7 @@ static void random_work(struct work_struct *work)
                       SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
 
                hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
-                           HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size,
+                           HCI_SMP_STK_SLAVE, 0, stk, smp->enc_key_size,
                            ediv, rand);
        }
 
@@ -479,6 +549,20 @@ error:
        smp_failure(conn, reason);
 }
 
+static void smp_reencrypt(struct work_struct *work)
+{
+       struct smp_chan *smp = container_of(work, struct smp_chan,
+                                           reencrypt.work);
+       struct l2cap_conn *conn = smp->conn;
+       struct hci_conn *hcon = conn->hcon;
+       struct smp_ltk *ltk = smp->ltk;
+
+       BT_DBG("");
+
+       hci_le_start_enc(hcon, ltk->ediv, ltk->rand, ltk->val);
+       hcon->enc_key_size = ltk->enc_size;
+}
+
 static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 {
        struct smp_chan *smp;
@@ -489,6 +573,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 
        INIT_WORK(&smp->confirm, confirm_work);
        INIT_WORK(&smp->random, random_work);
+       INIT_DELAYED_WORK(&smp->reencrypt, smp_reencrypt);
 
        smp->conn = conn;
        conn->smp_chan = smp;
@@ -502,11 +587,32 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 void smp_chan_destroy(struct l2cap_conn *conn)
 {
        struct smp_chan *smp = conn->smp_chan;
+       bool complete;
 
        BUG_ON(!smp);
 
-       if (smp->tfm)
-               crypto_free_blkcipher(smp->tfm);
+       cancel_delayed_work_sync(&smp->reencrypt);
+
+       complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
+       mgmt_smp_complete(conn->hcon, complete);
+
+       /* If pairing failed clean up any keys we might have */
+       if (!complete) {
+               if (smp->ltk) {
+                       list_del(&smp->ltk->list);
+                       kfree(smp->ltk);
+               }
+
+               if (smp->slave_ltk) {
+                       list_del(&smp->slave_ltk->list);
+                       kfree(smp->slave_ltk);
+               }
+
+               if (smp->remote_irk) {
+                       list_del(&smp->remote_irk->list);
+                       kfree(smp->remote_irk);
+               }
+       }
 
        kfree(smp);
        conn->smp_chan = NULL;
@@ -565,6 +671,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
        BT_DBG("conn %p", conn);
 
+       if (skb->len < sizeof(*req))
+               return SMP_UNSPECIFIED;
+
        if (conn->hcon->link_mode & HCI_LM_MASTER)
                return SMP_CMD_NOTSUPP;
 
@@ -617,6 +726,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
        BT_DBG("conn %p", conn);
 
+       if (skb->len < sizeof(*rsp))
+               return SMP_UNSPECIFIED;
+
        if (!(conn->hcon->link_mode & HCI_LM_MASTER))
                return SMP_CMD_NOTSUPP;
 
@@ -661,6 +773,9 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 
        BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
 
+       if (skb->len < sizeof(smp->pcnf))
+               return SMP_UNSPECIFIED;
+
        memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
        skb_pull(skb, sizeof(smp->pcnf));
 
@@ -686,6 +801,9 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 
        BT_DBG("conn %p", conn);
 
+       if (skb->len < sizeof(smp->rrnd))
+               return SMP_UNSPECIFIED;
+
        swap128(skb->data, smp->rrnd);
        skb_pull(skb, sizeof(smp->rrnd));
 
@@ -699,7 +817,8 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
        struct smp_ltk *key;
        struct hci_conn *hcon = conn->hcon;
 
-       key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type);
+       key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type,
+                                  hcon->out);
        if (!key)
                return 0;
 
@@ -724,6 +843,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
        BT_DBG("conn %p", conn);
 
+       if (skb->len < sizeof(*rp))
+               return SMP_UNSPECIFIED;
+
        if (!(conn->hcon->link_mode & HCI_LM_MASTER))
                return SMP_CMD_NOTSUPP;
 
@@ -813,6 +935,15 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
        struct smp_cmd_encrypt_info *rp = (void *) skb->data;
        struct smp_chan *smp = conn->smp_chan;
 
+       BT_DBG("conn %p", conn);
+
+       if (skb->len < sizeof(*rp))
+               return SMP_UNSPECIFIED;
+
+       /* Ignore this PDU if it wasn't requested */
+       if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
+               return 0;
+
        skb_pull(skb, sizeof(*rp));
 
        memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
@@ -826,21 +957,114 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
        struct smp_chan *smp = conn->smp_chan;
        struct hci_dev *hdev = conn->hcon->hdev;
        struct hci_conn *hcon = conn->hcon;
+       struct smp_ltk *ltk;
        u8 authenticated;
 
+       BT_DBG("conn %p", conn);
+
+       if (skb->len < sizeof(*rp))
+               return SMP_UNSPECIFIED;
+
+       /* Ignore this PDU if it wasn't requested */
+       if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
+               return 0;
+
+       /* Mark the information as received */
+       smp->remote_key_dist &= ~SMP_DIST_ENC_KEY;
+
        skb_pull(skb, sizeof(*rp));
 
        hci_dev_lock(hdev);
        authenticated = (hcon->sec_level == BT_SECURITY_HIGH);
-       hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1,
-                   authenticated, smp->tk, smp->enc_key_size,
-                   rp->ediv, rp->rand);
-       smp_distribute_keys(conn, 1);
+       ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK,
+                         authenticated, smp->tk, smp->enc_key_size,
+                         rp->ediv, rp->rand);
+       smp->ltk = ltk;
+       if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
+               smp_distribute_keys(conn);
        hci_dev_unlock(hdev);
 
        return 0;
 }
 
+static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+       struct smp_cmd_ident_info *info = (void *) skb->data;
+       struct smp_chan *smp = conn->smp_chan;
+
+       BT_DBG("");
+
+       if (skb->len < sizeof(*info))
+               return SMP_UNSPECIFIED;
+
+       /* Ignore this PDU if it wasn't requested */
+       if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
+               return 0;
+
+       skb_pull(skb, sizeof(*info));
+
+       memcpy(smp->irk, info->irk, 16);
+
+       return 0;
+}
+
+static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
+                                  struct sk_buff *skb)
+{
+       struct smp_cmd_ident_addr_info *info = (void *) skb->data;
+       struct smp_chan *smp = conn->smp_chan;
+       struct hci_conn *hcon = conn->hcon;
+       bdaddr_t rpa;
+
+       BT_DBG("");
+
+       if (skb->len < sizeof(*info))
+               return SMP_UNSPECIFIED;
+
+       /* Ignore this PDU if it wasn't requested */
+       if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
+               return 0;
+
+       /* Mark the information as received */
+       smp->remote_key_dist &= ~SMP_DIST_ID_KEY;
+
+       skb_pull(skb, sizeof(*info));
+
+       /* Strictly speaking the Core Specification (4.1) allows sending
+        * an empty address which would force us to rely on just the IRK
+        * as "identity information". However, since such
+        * implementations are not known of and in order to not over
+        * complicate our implementation, simply pretend that we never
+        * received an IRK for such a device.
+        */
+       if (!bacmp(&info->bdaddr, BDADDR_ANY)) {
+               BT_ERR("Ignoring IRK with no identity address");
+               smp_distribute_keys(conn);
+               return 0;
+       }
+
+       bacpy(&smp->id_addr, &info->bdaddr);
+       smp->id_addr_type = info->addr_type;
+
+       if (hci_bdaddr_is_rpa(&hcon->dst, hcon->dst_type))
+               bacpy(&rpa, &hcon->dst);
+       else
+               bacpy(&rpa, BDADDR_ANY);
+
+       smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr,
+                                     smp->id_addr_type, smp->irk, &rpa);
+
+       /* Track the connection based on the Identity Address from now on */
+       bacpy(&hcon->dst, &smp->id_addr);
+       hcon->dst_type = smp->id_addr_type;
+
+       l2cap_conn_update_id_addr(hcon);
+
+       smp_distribute_keys(conn);
+
+       return 0;
+}
+
 int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct hci_conn *hcon = conn->hcon;
@@ -915,7 +1139,13 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
                break;
 
        case SMP_CMD_IDENT_INFO:
+               reason = smp_cmd_ident_info(conn, skb);
+               break;
+
        case SMP_CMD_IDENT_ADDR_INFO:
+               reason = smp_cmd_ident_addr_info(conn, skb);
+               break;
+
        case SMP_CMD_SIGN_INFO:
                /* Just ignored */
                reason = 0;
@@ -937,26 +1167,51 @@ done:
        return err;
 }
 
-int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
+static void smp_notify_keys(struct l2cap_conn *conn)
+{
+       struct smp_chan *smp = conn->smp_chan;
+       struct hci_conn *hcon = conn->hcon;
+       struct hci_dev *hdev = hcon->hdev;
+
+       if (smp->remote_irk)
+               mgmt_new_irk(hdev, smp->remote_irk);
+
+       if (smp->ltk) {
+               smp->ltk->bdaddr_type = hcon->dst_type;
+               bacpy(&smp->ltk->bdaddr, &hcon->dst);
+               mgmt_new_ltk(hdev, smp->ltk);
+       }
+
+       if (smp->slave_ltk) {
+               smp->slave_ltk->bdaddr_type = hcon->dst_type;
+               bacpy(&smp->slave_ltk->bdaddr, &hcon->dst);
+               mgmt_new_ltk(hdev, smp->slave_ltk);
+       }
+}
+
+int smp_distribute_keys(struct l2cap_conn *conn)
 {
        struct smp_cmd_pairing *req, *rsp;
        struct smp_chan *smp = conn->smp_chan;
+       struct hci_conn *hcon = conn->hcon;
+       struct hci_dev *hdev = hcon->hdev;
+       bool ltk_encrypt;
        __u8 *keydist;
 
-       BT_DBG("conn %p force %d", conn, force);
+       BT_DBG("conn %p", conn);
 
-       if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
+       if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
                return 0;
 
        rsp = (void *) &smp->prsp[1];
 
        /* The responder sends its keys first */
-       if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
+       if (hcon->out && (smp->remote_key_dist & 0x07))
                return 0;
 
        req = (void *) &smp->preq[1];
 
-       if (conn->hcon->out) {
+       if (hcon->out) {
                keydist = &rsp->init_key_dist;
                *keydist &= req->init_key_dist;
        } else {
@@ -964,28 +1219,30 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
                *keydist &= req->resp_key_dist;
        }
 
-
        BT_DBG("keydist 0x%x", *keydist);
 
        if (*keydist & SMP_DIST_ENC_KEY) {
                struct smp_cmd_encrypt_info enc;
                struct smp_cmd_master_ident ident;
-               struct hci_conn *hcon = conn->hcon;
+               struct smp_ltk *ltk;
                u8 authenticated;
                __le16 ediv;
+               __le64 rand;
 
                get_random_bytes(enc.ltk, sizeof(enc.ltk));
                get_random_bytes(&ediv, sizeof(ediv));
-               get_random_bytes(ident.rand, sizeof(ident.rand));
+               get_random_bytes(&rand, sizeof(rand));
 
                smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
 
                authenticated = hcon->sec_level == BT_SECURITY_HIGH;
-               hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
-                           HCI_SMP_LTK_SLAVE, 1, authenticated,
-                           enc.ltk, smp->enc_key_size, ediv, ident.rand);
+               ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
+                                 HCI_SMP_LTK_SLAVE, authenticated, enc.ltk,
+                                 smp->enc_key_size, ediv, rand);
+               smp->slave_ltk = ltk;
 
                ident.ediv = ediv;
+               ident.rand = rand;
 
                smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
 
@@ -996,14 +1253,18 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
                struct smp_cmd_ident_addr_info addrinfo;
                struct smp_cmd_ident_info idinfo;
 
-               /* Send a dummy key */
-               get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
+               memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk));
 
                smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
 
-               /* Just public address */
-               memset(&addrinfo, 0, sizeof(addrinfo));
-               bacpy(&addrinfo.bdaddr, &conn->hcon->src);
+               /* The hci_conn contains the local identity address
+                * after the connection has been established.
+                *
+                * This is true even when the connection has been
+                * established using a resolvable random address.
+                */
+               bacpy(&addrinfo.bdaddr, &hcon->src);
+               addrinfo.addr_type = hcon->src_type;
 
                smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
                             &addrinfo);
@@ -1022,9 +1283,34 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
                *keydist &= ~SMP_DIST_SIGN;
        }
 
-       if (conn->hcon->out || force) {
-               clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
+       /* If there are still keys to be received wait for them */
+       if ((smp->remote_key_dist & 0x07))
+               return 0;
+
+       /* Check if we should try to re-encrypt the link with the LTK.
+        * SMP_FLAG_LTK_ENCRYPT flag is used to track whether we've
+        * already tried this (in which case we shouldn't try again).
+        *
+        * The request will trigger an encryption key refresh event
+        * which will cause a call to auth_cfm and eventually lead to
+        * l2cap_core.c calling this smp_distribute_keys function again
+        * and thereby completing the process.
+        */
+       if (smp->ltk)
+               ltk_encrypt = !test_and_set_bit(SMP_FLAG_LTK_ENCRYPT,
+                                               &smp->smp_flags);
+       else
+               ltk_encrypt = false;
+
+       /* Re-encrypt the link with LTK if possible */
+       if (ltk_encrypt && hcon->out) {
+               queue_delayed_work(hdev->req_workqueue, &smp->reencrypt,
+                                  SMP_REENCRYPT_TIMEOUT);
+       } else {
+               clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
                cancel_delayed_work_sync(&conn->security_timer);
+               set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
+               smp_notify_keys(conn);
                smp_chan_destroy(conn);
        }
 
index a700bcb490d7bedb24c55b0b97b58bc6280c5552..f55d836172182d81e21de7f1235b2184ee2f5f47 100644 (file)
@@ -78,7 +78,7 @@ struct smp_cmd_encrypt_info {
 #define SMP_CMD_MASTER_IDENT   0x07
 struct smp_cmd_master_ident {
        __le16  ediv;
-       __u8    rand[8];
+       __le64  rand;
 } __packed;
 
 #define SMP_CMD_IDENT_INFO     0x08
@@ -118,6 +118,10 @@ struct smp_cmd_security_req {
 #define SMP_FLAG_TK_VALID      1
 #define SMP_FLAG_CFM_PENDING   2
 #define SMP_FLAG_MITM_AUTH     3
+#define SMP_FLAG_LTK_ENCRYPT   4
+#define SMP_FLAG_COMPLETE      5
+
+#define SMP_REENCRYPT_TIMEOUT  msecs_to_jiffies(250)
 
 struct smp_chan {
        struct l2cap_conn *conn;
@@ -128,20 +132,30 @@ struct smp_chan {
        u8              pcnf[16]; /* SMP Pairing Confirm */
        u8              tk[16]; /* SMP Temporary Key */
        u8              enc_key_size;
+       u8              remote_key_dist;
+       bdaddr_t        id_addr;
+       u8              id_addr_type;
+       u8              irk[16];
+       struct smp_ltk  *ltk;
+       struct smp_ltk  *slave_ltk;
+       struct smp_irk  *remote_irk;
        unsigned long   smp_flags;
-       struct crypto_blkcipher *tfm;
        struct work_struct confirm;
        struct work_struct random;
-
+       struct delayed_work reencrypt;
 };
 
 /* SMP Commands */
 bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level);
 int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
 int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
-int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
+int smp_distribute_keys(struct l2cap_conn *conn);
 int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
 
 void smp_chan_destroy(struct l2cap_conn *conn);
 
+bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
+                    bdaddr_t *bdaddr);
+int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa);
+
 #endif /* __SMP_H */
index b063050b63e2926eb88845b56b45ab708cc9af3e..f2a08477e0f5c4b15445e86c3f27c96b9035be59 100644 (file)
@@ -136,9 +136,9 @@ static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev,
                const struct pcpu_sw_netstats *bstats
                        = per_cpu_ptr(br->stats, cpu);
                do {
-                       start = u64_stats_fetch_begin_bh(&bstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&bstats->syncp);
                        memcpy(&tmp, bstats, sizeof(tmp));
-               } while (u64_stats_fetch_retry_bh(&bstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&bstats->syncp, start));
                sum.tx_bytes   += tmp.tx_bytes;
                sum.tx_packets += tmp.tx_packets;
                sum.rx_bytes   += tmp.rx_bytes;
index c97c3c8ccdfb9f95e3ed31a22b30e400e8e31c19..7b757b5dc773fc2dcaedfa8f7c97e7884a622d89 100644 (file)
@@ -1127,9 +1127,10 @@ static void br_multicast_query_received(struct net_bridge *br,
                                        struct net_bridge_port *port,
                                        struct bridge_mcast_querier *querier,
                                        int saddr,
+                                       bool is_general_query,
                                        unsigned long max_delay)
 {
-       if (saddr)
+       if (saddr && is_general_query)
                br_multicast_update_querier_timer(br, querier, max_delay);
        else if (timer_pending(&querier->timer))
                return;
@@ -1181,8 +1182,16 @@ static int br_ip4_multicast_query(struct net_bridge *br,
                            IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
        }
 
+       /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer
+        * all-systems destination addresses (224.0.0.1) for general queries
+        */
+       if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr,
-                                   max_delay);
+                                   !group, max_delay);
 
        if (!group)
                goto out;
@@ -1228,6 +1237,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        unsigned long max_delay;
        unsigned long now = jiffies;
        const struct in6_addr *group = NULL;
+       bool is_general_query;
        int err = 0;
 
        spin_lock(&br->multicast_lock);
@@ -1235,6 +1245,12 @@ static int br_ip6_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
+       /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
+       if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        if (skb->len == sizeof(*mld)) {
                if (!pskb_may_pull(skb, sizeof(*mld))) {
                        err = -EINVAL;
@@ -1256,8 +1272,19 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL);
        }
 
+       is_general_query = group && ipv6_addr_any(group);
+
+       /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer
+        * all-nodes destination address (ff02::1) for general queries
+        */
+       if (is_general_query && !ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        br_multicast_query_received(br, port, &br->ip6_querier,
-                                   !ipv6_addr_any(&ip6h->saddr), max_delay);
+                                   !ipv6_addr_any(&ip6h->saddr),
+                                   is_general_query, max_delay);
 
        if (!group)
                goto out;
index df0f114fb8cb8c8e4ebdb4009fde8c2908f7d2b4..80e1b0f60a30214002684a42b1bab1a02e9d9962 100644 (file)
@@ -167,7 +167,7 @@ void br_netfilter_rtable_init(struct net_bridge *br)
        rt->dst.dev = br->dev;
        rt->dst.path = &rt->dst;
        dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
-       rt->dst.flags   = DST_NOXFRM | DST_NOPEER | DST_FAKE_RTABLE;
+       rt->dst.flags   = DST_NOXFRM | DST_FAKE_RTABLE;
        rt->dst.ops = &fake_dst_ops;
 }
 
index 8be757cca2ec444171982cb8c33ef58ab27310be..081e81fd017fa53f7a6ed3afd341601b43377531 100644 (file)
@@ -121,13 +121,9 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
        if (!ro->recv_own_msgs && oskb->sk == sk)
                return;
 
-       /* do not pass frames with DLC > 8 to a legacy socket */
-       if (!ro->fd_frames) {
-               struct canfd_frame *cfd = (struct canfd_frame *)oskb->data;
-
-               if (unlikely(cfd->len > CAN_MAX_DLEN))
-                       return;
-       }
+       /* do not pass non-CAN2.0 frames to a legacy socket */
+       if (!ro->fd_frames && oskb->len != CAN_MTU)
+               return;
 
        /* clone the given skb to be able to enqueue it into the rcv queue */
        skb = skb_clone(oskb, GFP_ATOMIC);
@@ -738,9 +734,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
                       struct msghdr *msg, size_t size, int flags)
 {
        struct sock *sk = sock->sk;
-       struct raw_sock *ro = raw_sk(sk);
        struct sk_buff *skb;
-       int rxmtu;
        int err = 0;
        int noblock;
 
@@ -751,20 +745,10 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (!skb)
                return err;
 
-       /*
-        * when serving a legacy socket the DLC <= 8 is already checked inside
-        * raw_rcv(). Now check if we need to pass a canfd_frame to a legacy
-        * socket and cut the possible CANFD_MTU/CAN_MTU length to CAN_MTU
-        */
-       if (!ro->fd_frames)
-               rxmtu = CAN_MTU;
-       else
-               rxmtu = skb->len;
-
-       if (size < rxmtu)
+       if (size < skb->len)
                msg->msg_flags |= MSG_TRUNC;
        else
-               size = rxmtu;
+               size = skb->len;
 
        err = memcpy_toiovec(msg->msg_iov, skb->data, size);
        if (err < 0) {
index b1b0c8d4d7df31d34a575ab326dab71f1a315e51..55f8e64c03a2cb8aa5364addc2ac7908f754f20a 100644 (file)
@@ -3231,10 +3231,6 @@ static int netif_rx_internal(struct sk_buff *skb)
 {
        int ret;
 
-       /* if netpoll wants it, pretend we never saw it */
-       if (netpoll_rx(skb))
-               return NET_RX_DROP;
-
        net_timestamp_check(netdev_tstamp_prequeue, skb);
 
        trace_netif_rx(skb);
@@ -3495,11 +3491,11 @@ EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
 static bool skb_pfmemalloc_protocol(struct sk_buff *skb)
 {
        switch (skb->protocol) {
-       case __constant_htons(ETH_P_ARP):
-       case __constant_htons(ETH_P_IP):
-       case __constant_htons(ETH_P_IPV6):
-       case __constant_htons(ETH_P_8021Q):
-       case __constant_htons(ETH_P_8021AD):
+       case htons(ETH_P_ARP):
+       case htons(ETH_P_IP):
+       case htons(ETH_P_IPV6):
+       case htons(ETH_P_8021Q):
+       case htons(ETH_P_8021AD):
                return true;
        default:
                return false;
@@ -3520,10 +3516,6 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
 
        trace_netif_receive_skb(skb);
 
-       /* if we've gotten here through NAPI, check netpoll */
-       if (netpoll_receive_skb(skb))
-               goto out;
-
        orig_dev = skb->dev;
 
        skb_reset_network_header(skb);
@@ -3650,7 +3642,6 @@ drop:
 
 unlock:
        rcu_read_unlock();
-out:
        return ret;
 }
 
@@ -3875,7 +3866,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
        int same_flow;
        enum gro_result ret;
 
-       if (!(skb->dev->features & NETIF_F_GRO) || netpoll_rx_on(skb))
+       if (!(skb->dev->features & NETIF_F_GRO))
                goto normal;
 
        if (skb_is_gso(skb) || skb_has_frag_list(skb))
index 344a184011fd014e354de4304b127eeeb0ec0f5a..31cfb365e0c689ffa528bf2f96072c6bcbc82799 100644 (file)
@@ -45,6 +45,8 @@ struct flow_flush_info {
        struct completion               completion;
 };
 
+static struct kmem_cache *flow_cachep __read_mostly;
+
 #define flow_cache_hash_size(cache)    (1 << (cache)->hash_shift)
 #define FLOW_HASH_RND_PERIOD           (10 * 60 * HZ)
 
@@ -75,7 +77,7 @@ static void flow_entry_kill(struct flow_cache_entry *fle,
 {
        if (fle->object)
                fle->object->ops->delete(fle->object);
-       kmem_cache_free(xfrm->flow_cachep, fle);
+       kmem_cache_free(flow_cachep, fle);
 }
 
 static void flow_cache_gc_task(struct work_struct *work)
@@ -230,7 +232,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
                if (fcp->hash_count > fc->high_watermark)
                        flow_cache_shrink(fc, fcp);
 
-               fle = kmem_cache_alloc(net->xfrm.flow_cachep, GFP_ATOMIC);
+               fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC);
                if (fle) {
                        fle->net = net;
                        fle->family = family;
@@ -435,10 +437,10 @@ int flow_cache_init(struct net *net)
        int i;
        struct flow_cache *fc = &net->xfrm.flow_cache_global;
 
-       /* Initialize per-net flow cache global variables here */
-       net->xfrm.flow_cachep = kmem_cache_create("flow_cache",
-                                       sizeof(struct flow_cache_entry),
-                                       0, SLAB_PANIC, NULL);
+       if (!flow_cachep)
+               flow_cachep = kmem_cache_create("flow_cache",
+                                               sizeof(struct flow_cache_entry),
+                                               0, SLAB_PANIC, NULL);
        spin_lock_init(&net->xfrm.flow_cache_gc_lock);
        INIT_LIST_HEAD(&net->xfrm.flow_cache_gc_list);
        INIT_WORK(&net->xfrm.flow_cache_gc_work, flow_cache_gc_task);
@@ -482,3 +484,22 @@ err:
        return -ENOMEM;
 }
 EXPORT_SYMBOL(flow_cache_init);
+
+void flow_cache_fini(struct net *net)
+{
+       int i;
+       struct flow_cache *fc = &net->xfrm.flow_cache_global;
+
+       del_timer_sync(&fc->rnd_timer);
+       unregister_hotcpu_notifier(&fc->hotcpu_notifier);
+
+       for_each_possible_cpu(i) {
+               struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, i);
+               kfree(fcp->hash_table);
+               fcp->hash_table = NULL;
+       }
+
+       free_percpu(fc->percpu);
+       fc->percpu = NULL;
+}
+EXPORT_SYMBOL(flow_cache_fini);
index e29e810663d777ecee281b61fda8ec8dbdcbfb92..80201bf69d598c05bc2f454fdca5a2a149cee292 100644 (file)
@@ -61,7 +61,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
 
 again:
        switch (proto) {
-       case __constant_htons(ETH_P_IP): {
+       case htons(ETH_P_IP): {
                const struct iphdr *iph;
                struct iphdr _iph;
 ip:
@@ -77,7 +77,7 @@ ip:
                iph_to_flow_copy_addrs(flow, iph);
                break;
        }
-       case __constant_htons(ETH_P_IPV6): {
+       case htons(ETH_P_IPV6): {
                const struct ipv6hdr *iph;
                struct ipv6hdr _iph;
 ipv6:
@@ -91,8 +91,8 @@ ipv6:
                nhoff += sizeof(struct ipv6hdr);
                break;
        }
-       case __constant_htons(ETH_P_8021AD):
-       case __constant_htons(ETH_P_8021Q): {
+       case htons(ETH_P_8021AD):
+       case htons(ETH_P_8021Q): {
                const struct vlan_hdr *vlan;
                struct vlan_hdr _vlan;
 
@@ -104,7 +104,7 @@ ipv6:
                nhoff += sizeof(*vlan);
                goto again;
        }
-       case __constant_htons(ETH_P_PPP_SES): {
+       case htons(ETH_P_PPP_SES): {
                struct {
                        struct pppoe_hdr hdr;
                        __be16 proto;
@@ -115,9 +115,9 @@ ipv6:
                proto = hdr->proto;
                nhoff += PPPOE_SES_HLEN;
                switch (proto) {
-               case __constant_htons(PPP_IP):
+               case htons(PPP_IP):
                        goto ip;
-               case __constant_htons(PPP_IPV6):
+               case htons(PPP_IPV6):
                        goto ipv6;
                default:
                        return false;
index fbde4e3ce802a0f2e52f237acae865fc6ff5774a..8f8a96ef9f3f64ba519fe4c872d46c7b7c680ec9 100644 (file)
@@ -766,9 +766,6 @@ static void neigh_periodic_work(struct work_struct *work)
        nht = rcu_dereference_protected(tbl->nht,
                                        lockdep_is_held(&tbl->lock));
 
-       if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
-               goto out;
-
        /*
         *      periodically recompute ReachableTime from random function
         */
@@ -781,6 +778,9 @@ static void neigh_periodic_work(struct work_struct *work)
                                neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
        }
 
+       if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
+               goto out;
+
        for (i = 0 ; i < (1 << nht->hash_shift); i++) {
                np = &nht->hash_buckets[i];
 
@@ -3047,7 +3047,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
        if (!t)
                goto err;
 
-       for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) {
+       for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
                t->neigh_vars[i].data += (long) p;
                t->neigh_vars[i].extra1 = dev;
                t->neigh_vars[i].extra2 = p;
index a664f7829a6d16db4579789ca5b8c40654cc78d7..7291dde934690e1acbb62d89d86897630ed9d0b2 100644 (file)
 
 static struct sk_buff_head skb_pool;
 
-static atomic_t trapped;
-
 DEFINE_STATIC_SRCU(netpoll_srcu);
 
 #define USEC_PER_POLL  50
-#define NETPOLL_RX_ENABLED  1
-#define NETPOLL_RX_DROP     2
 
 #define MAX_SKB_SIZE                                                   \
        (sizeof(struct ethhdr) +                                        \
@@ -61,7 +57,6 @@ DEFINE_STATIC_SRCU(netpoll_srcu);
         MAX_UDP_CHUNK)
 
 static void zap_completion_queue(void);
-static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
 static void netpoll_async_cleanup(struct work_struct *work);
 
 static unsigned int carrier_timeout = 4;
@@ -109,25 +104,6 @@ static void queue_process(struct work_struct *work)
        }
 }
 
-static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh,
-                           unsigned short ulen, __be32 saddr, __be32 daddr)
-{
-       __wsum psum;
-
-       if (uh->check == 0 || skb_csum_unnecessary(skb))
-               return 0;
-
-       psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
-
-       if (skb->ip_summed == CHECKSUM_COMPLETE &&
-           !csum_fold(csum_add(psum, skb->csum)))
-               return 0;
-
-       skb->csum = psum;
-
-       return __skb_checksum_complete(skb);
-}
-
 /*
  * Check whether delayed processing was scheduled for our NIC. If so,
  * we attempt to grab the poll lock and use ->poll() to pump the card.
@@ -138,14 +114,8 @@ static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh,
  * trylock here and interrupts are already disabled in the softirq
  * case. Further, we test the poll_owner to avoid recursion on UP
  * systems where the lock doesn't exist.
- *
- * In cases where there is bi-directional communications, reading only
- * one message at a time can lead to packets being dropped by the
- * network adapter, forcing superfluous retries and possibly timeouts.
- * Thus, we set our budget to greater than 1.
  */
-static int poll_one_napi(struct netpoll_info *npinfo,
-                        struct napi_struct *napi, int budget)
+static int poll_one_napi(struct napi_struct *napi, int budget)
 {
        int work;
 
@@ -156,52 +126,35 @@ static int poll_one_napi(struct netpoll_info *npinfo,
        if (!test_bit(NAPI_STATE_SCHED, &napi->state))
                return budget;
 
-       npinfo->rx_flags |= NETPOLL_RX_DROP;
-       atomic_inc(&trapped);
        set_bit(NAPI_STATE_NPSVC, &napi->state);
 
        work = napi->poll(napi, budget);
+       WARN_ONCE(work > budget, "%pF exceeded budget in poll\n", napi->poll);
        trace_napi_poll(napi);
 
        clear_bit(NAPI_STATE_NPSVC, &napi->state);
-       atomic_dec(&trapped);
-       npinfo->rx_flags &= ~NETPOLL_RX_DROP;
 
        return budget - work;
 }
 
-static void poll_napi(struct net_device *dev)
+static void poll_napi(struct net_device *dev, int budget)
 {
        struct napi_struct *napi;
-       int budget = 16;
 
        list_for_each_entry(napi, &dev->napi_list, dev_list) {
                if (napi->poll_owner != smp_processor_id() &&
                    spin_trylock(&napi->poll_lock)) {
-                       budget = poll_one_napi(rcu_dereference_bh(dev->npinfo),
-                                              napi, budget);
+                       budget = poll_one_napi(napi, budget);
                        spin_unlock(&napi->poll_lock);
-
-                       if (!budget)
-                               break;
                }
        }
 }
 
-static void service_neigh_queue(struct netpoll_info *npi)
-{
-       if (npi) {
-               struct sk_buff *skb;
-
-               while ((skb = skb_dequeue(&npi->neigh_tx)))
-                       netpoll_neigh_reply(skb, npi);
-       }
-}
-
 static void netpoll_poll_dev(struct net_device *dev)
 {
        const struct net_device_ops *ops;
        struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo);
+       int budget = 0;
 
        /* Don't do any rx activity if the dev_lock mutex is held
         * the dev_open/close paths use this to block netpoll activity
@@ -224,27 +177,10 @@ static void netpoll_poll_dev(struct net_device *dev)
        /* Process pending work on NIC */
        ops->ndo_poll_controller(dev);
 
-       poll_napi(dev);
+       poll_napi(dev, budget);
 
        up(&ni->dev_lock);
 
-       if (dev->flags & IFF_SLAVE) {
-               if (ni) {
-                       struct net_device *bond_dev;
-                       struct sk_buff *skb;
-                       struct netpoll_info *bond_ni;
-
-                       bond_dev = netdev_master_upper_dev_get_rcu(dev);
-                       bond_ni = rcu_dereference_bh(bond_dev->npinfo);
-                       while ((skb = skb_dequeue(&ni->neigh_tx))) {
-                               skb->dev = bond_dev;
-                               skb_queue_tail(&bond_ni->neigh_tx, skb);
-                       }
-               }
-       }
-
-       service_neigh_queue(ni);
-
        zap_completion_queue();
 }
 
@@ -529,384 +465,6 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 }
 EXPORT_SYMBOL(netpoll_send_udp);
 
-static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
-{
-       int size, type = ARPOP_REPLY;
-       __be32 sip, tip;
-       unsigned char *sha;
-       struct sk_buff *send_skb;
-       struct netpoll *np, *tmp;
-       unsigned long flags;
-       int hlen, tlen;
-       int hits = 0, proto;
-
-       if (list_empty(&npinfo->rx_np))
-               return;
-
-       /* Before checking the packet, we do some early
-          inspection whether this is interesting at all */
-       spin_lock_irqsave(&npinfo->rx_lock, flags);
-       list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-               if (np->dev == skb->dev)
-                       hits++;
-       }
-       spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-
-       /* No netpoll struct is using this dev */
-       if (!hits)
-               return;
-
-       proto = ntohs(eth_hdr(skb)->h_proto);
-       if (proto == ETH_P_ARP) {
-               struct arphdr *arp;
-               unsigned char *arp_ptr;
-               /* No arp on this interface */
-               if (skb->dev->flags & IFF_NOARP)
-                       return;
-
-               if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
-                       return;
-
-               skb_reset_network_header(skb);
-               skb_reset_transport_header(skb);
-               arp = arp_hdr(skb);
-
-               if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
-                    arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
-                   arp->ar_pro != htons(ETH_P_IP) ||
-                   arp->ar_op != htons(ARPOP_REQUEST))
-                       return;
-
-               arp_ptr = (unsigned char *)(arp+1);
-               /* save the location of the src hw addr */
-               sha = arp_ptr;
-               arp_ptr += skb->dev->addr_len;
-               memcpy(&sip, arp_ptr, 4);
-               arp_ptr += 4;
-               /* If we actually cared about dst hw addr,
-                  it would get copied here */
-               arp_ptr += skb->dev->addr_len;
-               memcpy(&tip, arp_ptr, 4);
-
-               /* Should we ignore arp? */
-               if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
-                       return;
-
-               size = arp_hdr_len(skb->dev);
-
-               spin_lock_irqsave(&npinfo->rx_lock, flags);
-               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-                       if (tip != np->local_ip.ip)
-                               continue;
-
-                       hlen = LL_RESERVED_SPACE(np->dev);
-                       tlen = np->dev->needed_tailroom;
-                       send_skb = find_skb(np, size + hlen + tlen, hlen);
-                       if (!send_skb)
-                               continue;
-
-                       skb_reset_network_header(send_skb);
-                       arp = (struct arphdr *) skb_put(send_skb, size);
-                       send_skb->dev = skb->dev;
-                       send_skb->protocol = htons(ETH_P_ARP);
-
-                       /* Fill the device header for the ARP frame */
-                       if (dev_hard_header(send_skb, skb->dev, ETH_P_ARP,
-                                           sha, np->dev->dev_addr,
-                                           send_skb->len) < 0) {
-                               kfree_skb(send_skb);
-                               continue;
-                       }
-
-                       /*
-                        * Fill out the arp protocol part.
-                        *
-                        * we only support ethernet device type,
-                        * which (according to RFC 1390) should
-                        * always equal 1 (Ethernet).
-                        */
-
-                       arp->ar_hrd = htons(np->dev->type);
-                       arp->ar_pro = htons(ETH_P_IP);
-                       arp->ar_hln = np->dev->addr_len;
-                       arp->ar_pln = 4;
-                       arp->ar_op = htons(type);
-
-                       arp_ptr = (unsigned char *)(arp + 1);
-                       memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
-                       arp_ptr += np->dev->addr_len;
-                       memcpy(arp_ptr, &tip, 4);
-                       arp_ptr += 4;
-                       memcpy(arp_ptr, sha, np->dev->addr_len);
-                       arp_ptr += np->dev->addr_len;
-                       memcpy(arp_ptr, &sip, 4);
-
-                       netpoll_send_skb(np, send_skb);
-
-                       /* If there are several rx_skb_hooks for the same
-                        * address we're fine by sending a single reply
-                        */
-                       break;
-               }
-               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-       } else if( proto == ETH_P_IPV6) {
-#if IS_ENABLED(CONFIG_IPV6)
-               struct nd_msg *msg;
-               u8 *lladdr = NULL;
-               struct ipv6hdr *hdr;
-               struct icmp6hdr *icmp6h;
-               const struct in6_addr *saddr;
-               const struct in6_addr *daddr;
-               struct inet6_dev *in6_dev = NULL;
-               struct in6_addr *target;
-
-               in6_dev = in6_dev_get(skb->dev);
-               if (!in6_dev || !in6_dev->cnf.accept_ra)
-                       return;
-
-               if (!pskb_may_pull(skb, skb->len))
-                       return;
-
-               msg = (struct nd_msg *)skb_transport_header(skb);
-
-               __skb_push(skb, skb->data - skb_transport_header(skb));
-
-               if (ipv6_hdr(skb)->hop_limit != 255)
-                       return;
-               if (msg->icmph.icmp6_code != 0)
-                       return;
-               if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
-                       return;
-
-               saddr = &ipv6_hdr(skb)->saddr;
-               daddr = &ipv6_hdr(skb)->daddr;
-
-               size = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
-
-               spin_lock_irqsave(&npinfo->rx_lock, flags);
-               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-                       if (!ipv6_addr_equal(daddr, &np->local_ip.in6))
-                               continue;
-
-                       hlen = LL_RESERVED_SPACE(np->dev);
-                       tlen = np->dev->needed_tailroom;
-                       send_skb = find_skb(np, size + hlen + tlen, hlen);
-                       if (!send_skb)
-                               continue;
-
-                       send_skb->protocol = htons(ETH_P_IPV6);
-                       send_skb->dev = skb->dev;
-
-                       skb_reset_network_header(send_skb);
-                       hdr = (struct ipv6hdr *) skb_put(send_skb, sizeof(struct ipv6hdr));
-                       *(__be32*)hdr = htonl(0x60000000);
-                       hdr->payload_len = htons(size);
-                       hdr->nexthdr = IPPROTO_ICMPV6;
-                       hdr->hop_limit = 255;
-                       hdr->saddr = *saddr;
-                       hdr->daddr = *daddr;
-
-                       icmp6h = (struct icmp6hdr *) skb_put(send_skb, sizeof(struct icmp6hdr));
-                       icmp6h->icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
-                       icmp6h->icmp6_router = 0;
-                       icmp6h->icmp6_solicited = 1;
-
-                       target = (struct in6_addr *) skb_put(send_skb, sizeof(struct in6_addr));
-                       *target = msg->target;
-                       icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, size,
-                                                             IPPROTO_ICMPV6,
-                                                             csum_partial(icmp6h,
-                                                                          size, 0));
-
-                       if (dev_hard_header(send_skb, skb->dev, ETH_P_IPV6,
-                                           lladdr, np->dev->dev_addr,
-                                           send_skb->len) < 0) {
-                               kfree_skb(send_skb);
-                               continue;
-                       }
-
-                       netpoll_send_skb(np, send_skb);
-
-                       /* If there are several rx_skb_hooks for the same
-                        * address, we're fine by sending a single reply
-                        */
-                       break;
-               }
-               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-#endif
-       }
-}
-
-static bool pkt_is_ns(struct sk_buff *skb)
-{
-       struct nd_msg *msg;
-       struct ipv6hdr *hdr;
-
-       if (skb->protocol != htons(ETH_P_ARP))
-               return false;
-       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)))
-               return false;
-
-       msg = (struct nd_msg *)skb_transport_header(skb);
-       __skb_push(skb, skb->data - skb_transport_header(skb));
-       hdr = ipv6_hdr(skb);
-
-       if (hdr->nexthdr != IPPROTO_ICMPV6)
-               return false;
-       if (hdr->hop_limit != 255)
-               return false;
-       if (msg->icmph.icmp6_code != 0)
-               return false;
-       if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
-               return false;
-
-       return true;
-}
-
-int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
-{
-       int proto, len, ulen, data_len;
-       int hits = 0, offset;
-       const struct iphdr *iph;
-       struct udphdr *uh;
-       struct netpoll *np, *tmp;
-       uint16_t source;
-
-       if (list_empty(&npinfo->rx_np))
-               goto out;
-
-       if (skb->dev->type != ARPHRD_ETHER)
-               goto out;
-
-       /* check if netpoll clients need ARP */
-       if (skb->protocol == htons(ETH_P_ARP) && atomic_read(&trapped)) {
-               skb_queue_tail(&npinfo->neigh_tx, skb);
-               return 1;
-       } else if (pkt_is_ns(skb) && atomic_read(&trapped)) {
-               skb_queue_tail(&npinfo->neigh_tx, skb);
-               return 1;
-       }
-
-       if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
-               skb = vlan_untag(skb);
-               if (unlikely(!skb))
-                       goto out;
-       }
-
-       proto = ntohs(eth_hdr(skb)->h_proto);
-       if (proto != ETH_P_IP && proto != ETH_P_IPV6)
-               goto out;
-       if (skb->pkt_type == PACKET_OTHERHOST)
-               goto out;
-       if (skb_shared(skb))
-               goto out;
-
-       if (proto == ETH_P_IP) {
-               if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-                       goto out;
-               iph = (struct iphdr *)skb->data;
-               if (iph->ihl < 5 || iph->version != 4)
-                       goto out;
-               if (!pskb_may_pull(skb, iph->ihl*4))
-                       goto out;
-               iph = (struct iphdr *)skb->data;
-               if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
-                       goto out;
-
-               len = ntohs(iph->tot_len);
-               if (skb->len < len || len < iph->ihl*4)
-                       goto out;
-
-               /*
-                * Our transport medium may have padded the buffer out.
-                * Now We trim to the true length of the frame.
-                */
-               if (pskb_trim_rcsum(skb, len))
-                       goto out;
-
-               iph = (struct iphdr *)skb->data;
-               if (iph->protocol != IPPROTO_UDP)
-                       goto out;
-
-               len -= iph->ihl*4;
-               uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
-               offset = (unsigned char *)(uh + 1) - skb->data;
-               ulen = ntohs(uh->len);
-               data_len = skb->len - offset;
-               source = ntohs(uh->source);
-
-               if (ulen != len)
-                       goto out;
-               if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
-                       goto out;
-               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-                       if (np->local_ip.ip && np->local_ip.ip != iph->daddr)
-                               continue;
-                       if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr)
-                               continue;
-                       if (np->local_port && np->local_port != ntohs(uh->dest))
-                               continue;
-
-                       np->rx_skb_hook(np, source, skb, offset, data_len);
-                       hits++;
-               }
-       } else {
-#if IS_ENABLED(CONFIG_IPV6)
-               const struct ipv6hdr *ip6h;
-
-               if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
-                       goto out;
-               ip6h = (struct ipv6hdr *)skb->data;
-               if (ip6h->version != 6)
-                       goto out;
-               len = ntohs(ip6h->payload_len);
-               if (!len)
-                       goto out;
-               if (len + sizeof(struct ipv6hdr) > skb->len)
-                       goto out;
-               if (pskb_trim_rcsum(skb, len + sizeof(struct ipv6hdr)))
-                       goto out;
-               ip6h = ipv6_hdr(skb);
-               if (!pskb_may_pull(skb, sizeof(struct udphdr)))
-                       goto out;
-               uh = udp_hdr(skb);
-               offset = (unsigned char *)(uh + 1) - skb->data;
-               ulen = ntohs(uh->len);
-               data_len = skb->len - offset;
-               source = ntohs(uh->source);
-               if (ulen != skb->len)
-                       goto out;
-               if (udp6_csum_init(skb, uh, IPPROTO_UDP))
-                       goto out;
-               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-                       if (!ipv6_addr_equal(&np->local_ip.in6, &ip6h->daddr))
-                               continue;
-                       if (!ipv6_addr_equal(&np->remote_ip.in6, &ip6h->saddr))
-                               continue;
-                       if (np->local_port && np->local_port != ntohs(uh->dest))
-                               continue;
-
-                       np->rx_skb_hook(np, source, skb, offset, data_len);
-                       hits++;
-               }
-#endif
-       }
-
-       if (!hits)
-               goto out;
-
-       kfree_skb(skb);
-       return 1;
-
-out:
-       if (atomic_read(&trapped)) {
-               kfree_skb(skb);
-               return 1;
-       }
-
-       return 0;
-}
-
 void netpoll_print_options(struct netpoll *np)
 {
        np_info(np, "local port %d\n", np->local_port);
@@ -1030,7 +588,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
 {
        struct netpoll_info *npinfo;
        const struct net_device_ops *ops;
-       unsigned long flags;
        int err;
 
        np->dev = ndev;
@@ -1052,12 +609,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
                        goto out;
                }
 
-               npinfo->rx_flags = 0;
-               INIT_LIST_HEAD(&npinfo->rx_np);
-
-               spin_lock_init(&npinfo->rx_lock);
                sema_init(&npinfo->dev_lock, 1);
-               skb_queue_head_init(&npinfo->neigh_tx);
                skb_queue_head_init(&npinfo->txq);
                INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
 
@@ -1076,13 +628,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
 
        npinfo->netpoll = np;
 
-       if (np->rx_skb_hook) {
-               spin_lock_irqsave(&npinfo->rx_lock, flags);
-               npinfo->rx_flags |= NETPOLL_RX_ENABLED;
-               list_add_tail(&np->rx, &npinfo->rx_np);
-               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-       }
-
        /* last thing to do is link it to the net device structure */
        rcu_assign_pointer(ndev->npinfo, npinfo);
 
@@ -1231,7 +776,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
        struct netpoll_info *npinfo =
                        container_of(rcu_head, struct netpoll_info, rcu);
 
-       skb_queue_purge(&npinfo->neigh_tx);
        skb_queue_purge(&npinfo->txq);
 
        /* we can't call cancel_delayed_work_sync here, as we are in softirq */
@@ -1247,7 +791,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
 void __netpoll_cleanup(struct netpoll *np)
 {
        struct netpoll_info *npinfo;
-       unsigned long flags;
 
        /* rtnl_dereference would be preferable here but
         * rcu_cleanup_netpoll path can put us in here safely without
@@ -1257,14 +800,6 @@ void __netpoll_cleanup(struct netpoll *np)
        if (!npinfo)
                return;
 
-       if (!list_empty(&npinfo->rx_np)) {
-               spin_lock_irqsave(&npinfo->rx_lock, flags);
-               list_del(&np->rx);
-               if (list_empty(&npinfo->rx_np))
-                       npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
-               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-       }
-
        synchronize_srcu(&netpoll_srcu);
 
        if (atomic_dec_and_test(&npinfo->refcnt)) {
@@ -1308,18 +843,3 @@ out:
        rtnl_unlock();
 }
 EXPORT_SYMBOL(netpoll_cleanup);
-
-int netpoll_trap(void)
-{
-       return atomic_read(&trapped);
-}
-EXPORT_SYMBOL(netpoll_trap);
-
-void netpoll_set_trap(int trap)
-{
-       if (trap)
-               atomic_inc(&trapped);
-       else
-               atomic_dec(&trapped);
-}
-EXPORT_SYMBOL(netpoll_set_trap);
index f28c37996aad9f2ee9a8a36ee44dd6497dd2e5d5..3f14c638c2b1961745ef513ab1c0e3a1dbfbbf4c 100644 (file)
@@ -707,9 +707,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->mark               = old->mark;
        new->skb_iif            = old->skb_iif;
        __nf_copy(new, old);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-       new->nf_trace           = old->nf_trace;
-#endif
 #ifdef CONFIG_NET_SCHED
        new->tc_index           = old->tc_index;
 #ifdef CONFIG_NET_CLS_ACT
@@ -2841,81 +2838,84 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
 
 /**
  *     skb_segment - Perform protocol segmentation on skb.
- *     @skb: buffer to segment
+ *     @head_skb: buffer to segment
  *     @features: features for the output path (see dev->features)
  *
  *     This function performs segmentation on the given skb.  It returns
  *     a pointer to the first in a list of new skbs for the segments.
  *     In case of error it returns ERR_PTR(err).
  */
-struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
+struct sk_buff *skb_segment(struct sk_buff *head_skb,
+                           netdev_features_t features)
 {
        struct sk_buff *segs = NULL;
        struct sk_buff *tail = NULL;
-       struct sk_buff *fskb = skb_shinfo(skb)->frag_list;
-       skb_frag_t *skb_frag = skb_shinfo(skb)->frags;
-       unsigned int mss = skb_shinfo(skb)->gso_size;
-       unsigned int doffset = skb->data - skb_mac_header(skb);
+       struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list;
+       skb_frag_t *frag = skb_shinfo(head_skb)->frags;
+       unsigned int mss = skb_shinfo(head_skb)->gso_size;
+       unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
+       struct sk_buff *frag_skb = head_skb;
        unsigned int offset = doffset;
-       unsigned int tnl_hlen = skb_tnl_header_len(skb);
+       unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
        unsigned int headroom;
        unsigned int len;
        __be16 proto;
        bool csum;
        int sg = !!(features & NETIF_F_SG);
-       int nfrags = skb_shinfo(skb)->nr_frags;
+       int nfrags = skb_shinfo(head_skb)->nr_frags;
        int err = -ENOMEM;
        int i = 0;
        int pos;
 
-       proto = skb_network_protocol(skb);
+       proto = skb_network_protocol(head_skb);
        if (unlikely(!proto))
                return ERR_PTR(-EINVAL);
 
        csum = !!can_checksum_protocol(features, proto);
-       __skb_push(skb, doffset);
-       headroom = skb_headroom(skb);
-       pos = skb_headlen(skb);
+       __skb_push(head_skb, doffset);
+       headroom = skb_headroom(head_skb);
+       pos = skb_headlen(head_skb);
 
        do {
                struct sk_buff *nskb;
-               skb_frag_t *frag;
+               skb_frag_t *nskb_frag;
                int hsize;
                int size;
 
-               len = skb->len - offset;
+               len = head_skb->len - offset;
                if (len > mss)
                        len = mss;
 
-               hsize = skb_headlen(skb) - offset;
+               hsize = skb_headlen(head_skb) - offset;
                if (hsize < 0)
                        hsize = 0;
                if (hsize > len || !sg)
                        hsize = len;
 
-               if (!hsize && i >= nfrags && skb_headlen(fskb) &&
-                   (skb_headlen(fskb) == len || sg)) {
-                       BUG_ON(skb_headlen(fskb) > len);
+               if (!hsize && i >= nfrags && skb_headlen(list_skb) &&
+                   (skb_headlen(list_skb) == len || sg)) {
+                       BUG_ON(skb_headlen(list_skb) > len);
 
                        i = 0;
-                       nfrags = skb_shinfo(fskb)->nr_frags;
-                       skb_frag = skb_shinfo(fskb)->frags;
-                       pos += skb_headlen(fskb);
+                       nfrags = skb_shinfo(list_skb)->nr_frags;
+                       frag = skb_shinfo(list_skb)->frags;
+                       frag_skb = list_skb;
+                       pos += skb_headlen(list_skb);
 
                        while (pos < offset + len) {
                                BUG_ON(i >= nfrags);
 
-                               size = skb_frag_size(skb_frag);
+                               size = skb_frag_size(frag);
                                if (pos + size > offset + len)
                                        break;
 
                                i++;
                                pos += size;
-                               skb_frag++;
+                               frag++;
                        }
 
-                       nskb = skb_clone(fskb, GFP_ATOMIC);
-                       fskb = fskb->next;
+                       nskb = skb_clone(list_skb, GFP_ATOMIC);
+                       list_skb = list_skb->next;
 
                        if (unlikely(!nskb))
                                goto err;
@@ -2936,7 +2936,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                        __skb_push(nskb, doffset);
                } else {
                        nskb = __alloc_skb(hsize + doffset + headroom,
-                                          GFP_ATOMIC, skb_alloc_rx_flag(skb),
+                                          GFP_ATOMIC, skb_alloc_rx_flag(head_skb),
                                           NUMA_NO_NODE);
 
                        if (unlikely(!nskb))
@@ -2952,12 +2952,12 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                        segs = nskb;
                tail = nskb;
 
-               __copy_skb_header(nskb, skb);
-               nskb->mac_len = skb->mac_len;
+               __copy_skb_header(nskb, head_skb);
+               nskb->mac_len = head_skb->mac_len;
 
                skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom);
 
-               skb_copy_from_linear_data_offset(skb, -tnl_hlen,
+               skb_copy_from_linear_data_offset(head_skb, -tnl_hlen,
                                                 nskb->data - tnl_hlen,
                                                 doffset + tnl_hlen);
 
@@ -2966,30 +2966,32 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
 
                if (!sg) {
                        nskb->ip_summed = CHECKSUM_NONE;
-                       nskb->csum = skb_copy_and_csum_bits(skb, offset,
+                       nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
                                                            skb_put(nskb, len),
                                                            len, 0);
                        continue;
                }
 
-               frag = skb_shinfo(nskb)->frags;
+               nskb_frag = skb_shinfo(nskb)->frags;
 
-               skb_copy_from_linear_data_offset(skb, offset,
+               skb_copy_from_linear_data_offset(head_skb, offset,
                                                 skb_put(nskb, hsize), hsize);
 
-               skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
+               skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags &
+                       SKBTX_SHARED_FRAG;
 
                while (pos < offset + len) {
                        if (i >= nfrags) {
-                               BUG_ON(skb_headlen(fskb));
+                               BUG_ON(skb_headlen(list_skb));
 
                                i = 0;
-                               nfrags = skb_shinfo(fskb)->nr_frags;
-                               skb_frag = skb_shinfo(fskb)->frags;
+                               nfrags = skb_shinfo(list_skb)->nr_frags;
+                               frag = skb_shinfo(list_skb)->frags;
+                               frag_skb = list_skb;
 
                                BUG_ON(!nfrags);
 
-                               fskb = fskb->next;
+                               list_skb = list_skb->next;
                        }
 
                        if (unlikely(skb_shinfo(nskb)->nr_frags >=
@@ -3000,27 +3002,30 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                                goto err;
                        }
 
-                       *frag = *skb_frag;
-                       __skb_frag_ref(frag);
-                       size = skb_frag_size(frag);
+                       if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC)))
+                               goto err;
+
+                       *nskb_frag = *frag;
+                       __skb_frag_ref(nskb_frag);
+                       size = skb_frag_size(nskb_frag);
 
                        if (pos < offset) {
-                               frag->page_offset += offset - pos;
-                               skb_frag_size_sub(frag, offset - pos);
+                               nskb_frag->page_offset += offset - pos;
+                               skb_frag_size_sub(nskb_frag, offset - pos);
                        }
 
                        skb_shinfo(nskb)->nr_frags++;
 
                        if (pos + size <= offset + len) {
                                i++;
-                               skb_frag++;
+                               frag++;
                                pos += size;
                        } else {
-                               skb_frag_size_sub(frag, pos + size - (offset + len));
+                               skb_frag_size_sub(nskb_frag, pos + size - (offset + len));
                                goto skip_fraglist;
                        }
 
-                       frag++;
+                       nskb_frag++;
                }
 
 skip_fraglist:
@@ -3034,7 +3039,7 @@ perform_csum_check:
                                                  nskb->len - doffset, 0);
                        nskb->ip_summed = CHECKSUM_NONE;
                }
-       } while ((offset += len) < skb->len);
+       } while ((offset += len) < head_skb->len);
 
        return segs;
 
@@ -3569,15 +3574,47 @@ static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len,
        return 0;
 }
 
+#define MAX_TCP_HDR_LEN (15 * 4)
+
+static __sum16 *skb_checksum_setup_ip(struct sk_buff *skb,
+                                     typeof(IPPROTO_IP) proto,
+                                     unsigned int off)
+{
+       switch (proto) {
+               int err;
+
+       case IPPROTO_TCP:
+               err = skb_maybe_pull_tail(skb, off + sizeof(struct tcphdr),
+                                         off + MAX_TCP_HDR_LEN);
+               if (!err && !skb_partial_csum_set(skb, off,
+                                                 offsetof(struct tcphdr,
+                                                          check)))
+                       err = -EPROTO;
+               return err ? ERR_PTR(err) : &tcp_hdr(skb)->check;
+
+       case IPPROTO_UDP:
+               err = skb_maybe_pull_tail(skb, off + sizeof(struct udphdr),
+                                         off + sizeof(struct udphdr));
+               if (!err && !skb_partial_csum_set(skb, off,
+                                                 offsetof(struct udphdr,
+                                                          check)))
+                       err = -EPROTO;
+               return err ? ERR_PTR(err) : &udp_hdr(skb)->check;
+       }
+
+       return ERR_PTR(-EPROTO);
+}
+
 /* 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)
+static int skb_checksum_setup_ipv4(struct sk_buff *skb, bool recalculate)
 {
        unsigned int off;
        bool fragment;
+       __sum16 *csum;
        int err;
 
        fragment = false;
@@ -3598,51 +3635,15 @@ static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate)
        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;
-       }
+       csum = skb_checksum_setup_ip(skb, ip_hdr(skb)->protocol, off);
+       if (IS_ERR(csum))
+               return PTR_ERR(csum);
 
+       if (recalculate)
+               *csum = ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+                                          ip_hdr(skb)->daddr,
+                                          skb->len - off,
+                                          ip_hdr(skb)->protocol, 0);
        err = 0;
 
 out:
@@ -3665,6 +3666,7 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate)
        unsigned int len;
        bool fragment;
        bool done;
+       __sum16 *csum;
 
        fragment = false;
        done = false;
@@ -3742,51 +3744,14 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate)
        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;
-       }
+       csum = skb_checksum_setup_ip(skb, nexthdr, off);
+       if (IS_ERR(csum))
+               return PTR_ERR(csum);
 
+       if (recalculate)
+               *csum = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                        &ipv6_hdr(skb)->daddr,
+                                        skb->len - off, nexthdr, 0);
        err = 0;
 
 out:
@@ -3804,7 +3769,7 @@ int skb_checksum_setup(struct sk_buff *skb, bool recalculate)
 
        switch (skb->protocol) {
        case htons(ETH_P_IP):
-               err = skb_checksum_setup_ip(skb, recalculate);
+               err = skb_checksum_setup_ipv4(skb, recalculate);
                break;
 
        case htons(ETH_P_IPV6):
index 5b6a9431b0176142cb1f93392a0294c468d84887..c0fc6bdad1e3629f123244d6d7c77805c9b5f0bd 100644 (file)
@@ -2357,10 +2357,13 @@ void release_sock(struct sock *sk)
        if (sk->sk_backlog.tail)
                __release_sock(sk);
 
+       /* Warning : release_cb() might need to release sk ownership,
+        * ie call sock_release_ownership(sk) before us.
+        */
        if (sk->sk_prot->release_cb)
                sk->sk_prot->release_cb(sk);
 
-       sk->sk_lock.owned = 0;
+       sock_release_ownership(sk);
        if (waitqueue_active(&sk->sk_lock.wq))
                wake_up(&sk->sk_lock.wq);
        spin_unlock_bh(&sk->sk_lock.slock);
index 3d0100f0bae3ea53be8395577fdf0fcd6edfaa1f..83e58449366a92bcc4e349241337914bca8dcd10 100644 (file)
@@ -297,7 +297,7 @@ static bool seq_nr_after(u16 a, u16 b)
 
 void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx)
 {
-       if ((dev_idx < 0) || (dev_idx >= HSR_MAX_DEV)) {
+       if ((dev_idx < 0) || (dev_idx >= HSR_MAX_SLAVE)) {
                WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx);
                return;
        }
diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
deleted file mode 100644 (file)
index 0dccf62..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef __6LOWPAN_H__
-#define __6LOWPAN_H__
-
-#define UIP_802154_SHORTADDR_LEN       2  /* compressed ipv6 address length */
-#define UIP_IPH_LEN                    40 /* ipv6 fixed header size */
-#define UIP_PROTO_UDP                  17 /* ipv6 next header value for UDP */
-#define UIP_FRAGH_LEN                  8  /* ipv6 fragment header size */
-
-/*
- * ipv6 address based on mac
- * second bit-flip (Universe/Local) is done according RFC2464
- */
-#define is_addr_mac_addr_based(a, m) \
-       ((((a)->s6_addr[8])  == (((m)[0]) ^ 0x02)) &&   \
-        (((a)->s6_addr[9])  == (m)[1]) &&              \
-        (((a)->s6_addr[10]) == (m)[2]) &&              \
-        (((a)->s6_addr[11]) == (m)[3]) &&              \
-        (((a)->s6_addr[12]) == (m)[4]) &&              \
-        (((a)->s6_addr[13]) == (m)[5]) &&              \
-        (((a)->s6_addr[14]) == (m)[6]) &&              \
-        (((a)->s6_addr[15]) == (m)[7]))
-
-/* ipv6 address is unspecified */
-#define is_addr_unspecified(a)         \
-       ((((a)->s6_addr32[0]) == 0) &&  \
-        (((a)->s6_addr32[1]) == 0) &&  \
-        (((a)->s6_addr32[2]) == 0) &&  \
-        (((a)->s6_addr32[3]) == 0))
-
-/* compare ipv6 addresses prefixes */
-#define ipaddr_prefixcmp(addr1, addr2, length) \
-       (memcmp(addr1, addr2, length >> 3) == 0)
-
-/* local link, i.e. FE80::/10 */
-#define is_addr_link_local(a) (((a)->s6_addr16[0]) == htons(0xFE80))
-
-/*
- * check whether we can compress the IID to 16 bits,
- * it's possible for unicast adresses with first 49 bits are zero only.
- */
-#define lowpan_is_iid_16_bit_compressable(a)   \
-       ((((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr[10]) == 0) &&           \
-        (((a)->s6_addr[11]) == 0xff) &&        \
-        (((a)->s6_addr[12]) == 0xfe) &&        \
-        (((a)->s6_addr[13]) == 0))
-
-/* multicast address */
-#define is_addr_mcast(a) (((a)->s6_addr[0]) == 0xFF)
-
-/* check whether the 112-bit gid of the multicast address is mappable to: */
-
-/* 9 bits, for FF02::1 (all nodes) and FF02::2 (all routers) addresses only. */
-#define lowpan_is_mcast_addr_compressable(a)   \
-       ((((a)->s6_addr16[1]) == 0) &&          \
-        (((a)->s6_addr16[2]) == 0) &&          \
-        (((a)->s6_addr16[3]) == 0) &&          \
-        (((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr16[5]) == 0) &&          \
-        (((a)->s6_addr16[6]) == 0) &&          \
-        (((a)->s6_addr[14])  == 0) &&          \
-        ((((a)->s6_addr[15]) == 1) || (((a)->s6_addr[15]) == 2)))
-
-/* 48 bits, FFXX::00XX:XXXX:XXXX */
-#define lowpan_is_mcast_addr_compressable48(a) \
-       ((((a)->s6_addr16[1]) == 0) &&          \
-        (((a)->s6_addr16[2]) == 0) &&          \
-        (((a)->s6_addr16[3]) == 0) &&          \
-        (((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr[10]) == 0))
-
-/* 32 bits, FFXX::00XX:XXXX */
-#define lowpan_is_mcast_addr_compressable32(a) \
-       ((((a)->s6_addr16[1]) == 0) &&          \
-        (((a)->s6_addr16[2]) == 0) &&          \
-        (((a)->s6_addr16[3]) == 0) &&          \
-        (((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr16[5]) == 0) &&          \
-        (((a)->s6_addr[12]) == 0))
-
-/* 8 bits, FF02::00XX */
-#define lowpan_is_mcast_addr_compressable8(a)  \
-       ((((a)->s6_addr[1])  == 2) &&           \
-        (((a)->s6_addr16[1]) == 0) &&          \
-        (((a)->s6_addr16[2]) == 0) &&          \
-        (((a)->s6_addr16[3]) == 0) &&          \
-        (((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr16[5]) == 0) &&          \
-        (((a)->s6_addr16[6]) == 0) &&          \
-        (((a)->s6_addr[14]) == 0))
-
-#define lowpan_is_addr_broadcast(a)    \
-       ((((a)[0]) == 0xFF) &&  \
-        (((a)[1]) == 0xFF) &&  \
-        (((a)[2]) == 0xFF) &&  \
-        (((a)[3]) == 0xFF) &&  \
-        (((a)[4]) == 0xFF) &&  \
-        (((a)[5]) == 0xFF) &&  \
-        (((a)[6]) == 0xFF) &&  \
-        (((a)[7]) == 0xFF))
-
-#define LOWPAN_DISPATCH_IPV6   0x41 /* 01000001 = 65 */
-#define LOWPAN_DISPATCH_HC1    0x42 /* 01000010 = 66 */
-#define LOWPAN_DISPATCH_IPHC   0x60 /* 011xxxxx = ... */
-#define LOWPAN_DISPATCH_FRAG1  0xc0 /* 11000xxx */
-#define LOWPAN_DISPATCH_FRAGN  0xe0 /* 11100xxx */
-
-#define LOWPAN_DISPATCH_MASK   0xf8 /* 11111000 */
-
-#define LOWPAN_FRAG_TIMEOUT    (HZ * 60)       /* time-out 60 sec */
-
-#define LOWPAN_FRAG1_HEAD_SIZE 0x4
-#define LOWPAN_FRAGN_HEAD_SIZE 0x5
-
-/*
- * According IEEE802.15.4 standard:
- *   - MTU is 127 octets
- *   - maximum MHR size is 37 octets
- *   - MFR size is 2 octets
- *
- * so minimal payload size that we may guarantee is:
- *   MTU - MHR - MFR = 88 octets
- */
-#define LOWPAN_FRAG_SIZE       88
-
-/*
- * Values of fields within the IPHC encoding first byte
- * (C stands for compressed and I for inline)
- */
-#define LOWPAN_IPHC_TF         0x18
-
-#define LOWPAN_IPHC_FL_C       0x10
-#define LOWPAN_IPHC_TC_C       0x08
-#define LOWPAN_IPHC_NH_C       0x04
-#define LOWPAN_IPHC_TTL_1      0x01
-#define LOWPAN_IPHC_TTL_64     0x02
-#define LOWPAN_IPHC_TTL_255    0x03
-#define LOWPAN_IPHC_TTL_I      0x00
-
-
-/* Values of fields within the IPHC encoding second byte */
-#define LOWPAN_IPHC_CID                0x80
-
-#define LOWPAN_IPHC_ADDR_00    0x00
-#define LOWPAN_IPHC_ADDR_01    0x01
-#define LOWPAN_IPHC_ADDR_02    0x02
-#define LOWPAN_IPHC_ADDR_03    0x03
-
-#define LOWPAN_IPHC_SAC                0x40
-#define LOWPAN_IPHC_SAM                0x30
-
-#define LOWPAN_IPHC_SAM_BIT    4
-
-#define LOWPAN_IPHC_M          0x08
-#define LOWPAN_IPHC_DAC                0x04
-#define LOWPAN_IPHC_DAM_00     0x00
-#define LOWPAN_IPHC_DAM_01     0x01
-#define LOWPAN_IPHC_DAM_10     0x02
-#define LOWPAN_IPHC_DAM_11     0x03
-
-#define LOWPAN_IPHC_DAM_BIT    0
-/*
- * LOWPAN_UDP encoding (works together with IPHC)
- */
-#define LOWPAN_NHC_UDP_MASK            0xF8
-#define LOWPAN_NHC_UDP_ID              0xF0
-#define LOWPAN_NHC_UDP_CHECKSUMC       0x04
-#define LOWPAN_NHC_UDP_CHECKSUMI       0x00
-
-#define LOWPAN_NHC_UDP_4BIT_PORT       0xF0B0
-#define LOWPAN_NHC_UDP_4BIT_MASK       0xFFF0
-#define LOWPAN_NHC_UDP_8BIT_PORT       0xF000
-#define LOWPAN_NHC_UDP_8BIT_MASK       0xFF00
-
-/* values for port compression, _with checksum_ ie bit 5 set to 0 */
-#define LOWPAN_NHC_UDP_CS_P_00 0xF0 /* all inline */
-#define LOWPAN_NHC_UDP_CS_P_01 0xF1 /* source 16bit inline,
-                                       dest = 0xF0 + 8 bit inline */
-#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)
-{
-       if (unlikely(!pskb_may_pull(skb, len)))
-               return true;
-
-       skb_copy_from_linear_data(skb, data, len);
-       skb_pull(skb, len);
-
-       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;
-}
-
-static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
-{
-       static const u8 addr_sizes[] = {
-               [LOWPAN_IPHC_ADDR_00] = 16,
-               [LOWPAN_IPHC_ADDR_01] = 8,
-               [LOWPAN_IPHC_ADDR_02] = 2,
-               [LOWPAN_IPHC_ADDR_03] = 0,
-       };
-       return addr_sizes[addr_mode];
-}
-
-static inline u8 lowpan_next_hdr_size(const u8 h_enc, u16 *uncomp_header)
-{
-       u8 ret = 1;
-
-       if ((h_enc & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
-               *uncomp_header += sizeof(struct udphdr);
-
-               switch (h_enc & LOWPAN_NHC_UDP_CS_P_11) {
-               case LOWPAN_NHC_UDP_CS_P_00:
-                       ret += 4;
-                       break;
-               case LOWPAN_NHC_UDP_CS_P_01:
-               case LOWPAN_NHC_UDP_CS_P_10:
-                       ret += 3;
-                       break;
-               case LOWPAN_NHC_UDP_CS_P_11:
-                       ret++;
-                       break;
-               default:
-                       break;
-               }
-
-               if (!(h_enc & LOWPAN_NHC_UDP_CS_C))
-                       ret += 2;
-       }
-
-       return ret;
-}
-
-/**
- *     lowpan_uncompress_size - returns skb->len size with uncompressed header
- *     @skb: sk_buff with 6lowpan header inside
- *     @datagram_offset: optional to get the datagram_offset value
- *
- *     Returns the skb->len with uncompressed header
- */
-static inline u16
-lowpan_uncompress_size(const struct sk_buff *skb, u16 *dgram_offset)
-{
-       u16 ret = 2, uncomp_header = sizeof(struct ipv6hdr);
-       u8 iphc0, iphc1, h_enc;
-
-       iphc0 = skb_network_header(skb)[0];
-       iphc1 = skb_network_header(skb)[1];
-
-       switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
-       case 0:
-               ret += 4;
-               break;
-       case 1:
-               ret += 3;
-               break;
-       case 2:
-               ret++;
-               break;
-       default:
-               break;
-       }
-
-       if (!(iphc0 & LOWPAN_IPHC_NH_C))
-               ret++;
-
-       if (!(iphc0 & 0x03))
-               ret++;
-
-       ret += lowpan_addr_mode_size((iphc1 & LOWPAN_IPHC_SAM) >>
-                                    LOWPAN_IPHC_SAM_BIT);
-
-       if (iphc1 & LOWPAN_IPHC_M) {
-               switch ((iphc1 & LOWPAN_IPHC_DAM_11) >>
-                       LOWPAN_IPHC_DAM_BIT) {
-               case LOWPAN_IPHC_DAM_00:
-                       ret += 16;
-                       break;
-               case LOWPAN_IPHC_DAM_01:
-                       ret += 6;
-                       break;
-               case LOWPAN_IPHC_DAM_10:
-                       ret += 4;
-                       break;
-               case LOWPAN_IPHC_DAM_11:
-                       ret++;
-                       break;
-               default:
-                       break;
-               }
-       } else {
-               ret += lowpan_addr_mode_size((iphc1 & LOWPAN_IPHC_DAM_11) >>
-                                            LOWPAN_IPHC_DAM_BIT);
-       }
-
-       if (iphc0 & LOWPAN_IPHC_NH_C) {
-               h_enc = skb_network_header(skb)[ret];
-               ret += lowpan_next_hdr_size(h_enc, &uncomp_header);
-       }
-
-       if (dgram_offset)
-               *dgram_offset = uncomp_header;
-
-       return skb->len + uncomp_header - ret;
-}
-
-typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev);
-
-int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
-               const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
-               const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
-               u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver);
-int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
-                       unsigned short type, const void *_daddr,
-                       const void *_saddr, unsigned int len);
-
-#endif /* __6LOWPAN_H__ */
index 860aa2d445bae361d5d588a6c1a4e41310d0d629..211b5686d719679242d6a7b5e0cd65547ae37cd3 100644 (file)
 #include <linux/if_arp.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
+#include <net/6lowpan.h>
 #include <net/ipv6.h>
 #include <net/af_ieee802154.h>
 
-#include "6lowpan.h"
-
 /*
  * Uncompress address function for source and
  * destination address(non-multicast).
index e4726180fc3635091fcf3c44e008e5d5d3c3021d..606039442a590ee400a5d55c5672a917dbc8352d 100644 (file)
 #include <net/af_ieee802154.h>
 #include <net/ieee802154.h>
 #include <net/ieee802154_netdev.h>
+#include <net/6lowpan.h>
 #include <net/ipv6.h>
 
 #include "reassembly.h"
-#include "6lowpan.h"
 
 static LIST_HEAD(lowpan_devices);
 
@@ -119,29 +119,29 @@ static int lowpan_header_create(struct sk_buff *skb,
        mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
 
        /* prepare wpan address data */
-       sa.addr_type = IEEE802154_ADDR_LONG;
+       sa.mode = IEEE802154_ADDR_LONG;
        sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+       sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
 
-       memcpy(&(sa.hwaddr), saddr, 8);
        /* intra-PAN communications */
-       da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+       da.pan_id = sa.pan_id;
 
        /* 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;
+               da.mode = IEEE802154_ADDR_SHORT;
+               da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
        } else {
-               da.addr_type = IEEE802154_ADDR_LONG;
-               memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN);
+               da.mode = IEEE802154_ADDR_LONG;
+               da.extended_addr = ieee802154_devaddr_from_raw(daddr);
 
                /* 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);
+                       type, (void *)&da, (void *)&sa, 0);
 }
 
 static int lowpan_give_skb_to_devices(struct sk_buff *skb,
@@ -168,10 +168,11 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb,
        return stat;
 }
 
-static int process_data(struct sk_buff *skb)
+static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
 {
        u8 iphc0, iphc1;
-       const struct ieee802154_addr *_saddr, *_daddr;
+       struct ieee802154_addr_sa sa, da;
+       void *sap, *dap;
 
        raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
        /* at least two bytes will be used for the encoding */
@@ -184,14 +185,23 @@ static int process_data(struct sk_buff *skb)
        if (lowpan_fetch_skb_u8(skb, &iphc1))
                goto drop;
 
-       _saddr = &mac_cb(skb)->sa;
-       _daddr = &mac_cb(skb)->da;
+       ieee802154_addr_to_sa(&sa, &hdr->source);
+       ieee802154_addr_to_sa(&da, &hdr->dest);
 
-       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);
+       if (sa.addr_type == IEEE802154_ADDR_SHORT)
+               sap = &sa.short_addr;
+       else
+               sap = &sa.hwaddr;
+
+       if (da.addr_type == IEEE802154_ADDR_SHORT)
+               dap = &da.short_addr;
+       else
+               dap = &da.hwaddr;
+
+       return lowpan_process_data(skb, skb->dev, sap, sa.addr_type,
+                                  IEEE802154_ADDR_LEN, dap, da.addr_type,
+                                  IEEE802154_ADDR_LEN, iphc0, iphc1,
+                                  lowpan_give_skb_to_devices);
 
 drop:
        kfree_skb(skb);
@@ -352,13 +362,13 @@ static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)
        return ieee802154_mlme_ops(real_dev)->get_phy(real_dev);
 }
 
-static u16 lowpan_get_pan_id(const struct net_device *dev)
+static __le16 lowpan_get_pan_id(const struct net_device *dev)
 {
        struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
        return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev);
 }
 
-static u16 lowpan_get_short_addr(const struct net_device *dev)
+static __le16 lowpan_get_short_addr(const struct net_device *dev)
 {
        struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
        return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev);
@@ -438,6 +448,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
        struct packet_type *pt, struct net_device *orig_dev)
 {
        struct sk_buff *local_skb;
+       struct ieee802154_hdr hdr;
        int ret;
 
        if (!netif_running(dev))
@@ -446,6 +457,9 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
        if (dev->type != ARPHRD_IEEE802154)
                goto drop_skb;
 
+       if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
+               goto drop_skb;
+
        local_skb = skb_clone(skb, GFP_ATOMIC);
        if (!local_skb)
                goto drop_skb;
@@ -466,14 +480,14 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
        } else {
                switch (skb->data[0] & 0xe0) {
                case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
-                       ret = process_data(local_skb);
+                       ret = process_data(local_skb, &hdr);
                        if (ret == NET_RX_DROP)
                                goto drop;
                        break;
                case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
                        ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAG1);
                        if (ret == 1) {
-                               ret = process_data(local_skb);
+                               ret = process_data(local_skb, &hdr);
                                if (ret == NET_RX_DROP)
                                        goto drop;
                        }
@@ -481,7 +495,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
                case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
                        ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAGN);
                        if (ret == 1) {
-                               ret = process_data(local_skb);
+                               ret = process_data(local_skb, &hdr);
                                if (ret == NET_RX_DROP)
                                        goto drop;
                        }
@@ -613,7 +627,7 @@ static struct notifier_block lowpan_dev_notifier = {
 };
 
 static struct packet_type lowpan_packet_type = {
-       .type = __constant_htons(ETH_P_IEEE802154),
+       .type = htons(ETH_P_IEEE802154),
        .func = lowpan_rcv,
 };
 
index 9c9879d5ea64e7e3e6fe04e1de3675d3ed3c256c..8af1330b3137b0282d316190770d77150f336d56 100644 (file)
@@ -15,7 +15,7 @@ config IEEE802154_6LOWPAN
        depends on IEEE802154 && IPV6
        select 6LOWPAN_IPHC
        ---help---
-       IPv6 compression over IEEE 802.15.4.
+         IPv6 compression over IEEE 802.15.4.
 
 config 6LOWPAN_IPHC
        tristate
index b113fc4be3e0e7f651b49b2fc955089deb78c8b2..bf1b51497a41048442640cf02d8de1f62c18ef6a 100644 (file)
@@ -3,5 +3,8 @@ obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o
 obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o
 
 6lowpan-y := 6lowpan_rtnl.o reassembly.o
-ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
+ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \
+                header_ops.o
 af_802154-y := af_ieee802154.o raw.o dgram.o
+
+ccflags-y += -D__CHECK_ENDIAN__
index b1ec5253752217f0f411383b9a61ad710ab74816..8330a09bfc95e6877351029cff36b542af11c66f 100644 (file)
 #define AF802154_H
 
 struct sk_buff;
-struct net_devce;
+struct net_device;
+struct ieee802154_addr;
 extern struct proto ieee802154_raw_prot;
 extern struct proto ieee802154_dgram_prot;
 void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb);
 int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb);
 struct net_device *ieee802154_get_dev(struct net *net,
-               struct ieee802154_addr *addr);
+                                     const struct ieee802154_addr *addr);
 
 #endif
index 40e606f3788f11f5dcdeb59420ff18a4ec24eab1..be44a86751aa7c74d5251d443267098646acfe46 100644 (file)
 /*
  * Utility function for families
  */
-struct net_device *ieee802154_get_dev(struct net *net,
-               struct ieee802154_addr *addr)
+struct net_device*
+ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
 {
        struct net_device *dev = NULL;
        struct net_device *tmp;
-       u16 pan_id, short_addr;
+       __le16 pan_id, short_addr;
+       u8 hwaddr[IEEE802154_ADDR_LEN];
 
-       switch (addr->addr_type) {
+       switch (addr->mode) {
        case IEEE802154_ADDR_LONG:
+               ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr);
                rcu_read_lock();
-               dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, addr->hwaddr);
+               dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr);
                if (dev)
                        dev_hold(dev);
                rcu_read_unlock();
                break;
        case IEEE802154_ADDR_SHORT:
-               if (addr->pan_id == 0xffff ||
-                   addr->short_addr == IEEE802154_ADDR_UNDEF ||
-                   addr->short_addr == 0xffff)
+               if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) ||
+                   addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
+                   addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF))
                        break;
 
                rtnl_lock();
@@ -86,7 +88,7 @@ struct net_device *ieee802154_get_dev(struct net *net,
                break;
        default:
                pr_warning("Unsupported ieee802154 address type: %d\n",
-                               addr->addr_type);
+                               addr->mode);
                break;
        }
 
@@ -326,7 +328,7 @@ drop:
 
 
 static struct packet_type ieee802154_packet_type = {
-       .type = __constant_htons(ETH_P_IEEE802154),
+       .type = htons(ETH_P_IEEE802154),
        .func = ieee802154_rcv,
 };
 
index 1846c1fe0d06a1f788c04b977b11f8eb70f84ce8..4c47154041b0bc5983506f8cf2d2586695ca438a 100644 (file)
@@ -73,10 +73,10 @@ static int dgram_init(struct sock *sk)
 {
        struct dgram_sock *ro = dgram_sk(sk);
 
-       ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
-       ro->dst_addr.pan_id = 0xffff;
+       ro->dst_addr.mode = IEEE802154_ADDR_LONG;
+       ro->dst_addr.pan_id = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
        ro->want_ack = 1;
-       memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+       memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
        return 0;
 }
 
@@ -88,6 +88,7 @@ static void dgram_close(struct sock *sk, long timeout)
 static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
 {
        struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+       struct ieee802154_addr haddr;
        struct dgram_sock *ro = dgram_sk(sk);
        int err = -EINVAL;
        struct net_device *dev;
@@ -102,7 +103,8 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
        if (addr->family != AF_IEEE802154)
                goto out;
 
-       dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
+       ieee802154_addr_from_sa(&haddr, &addr->addr);
+       dev = ieee802154_get_dev(sock_net(sk), &haddr);
        if (!dev) {
                err = -ENODEV;
                goto out;
@@ -113,7 +115,7 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
                goto out_put;
        }
 
-       memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr));
+       ro->src_addr = haddr;
 
        ro->bound = 1;
        err = 0;
@@ -149,8 +151,7 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
                         * of this packet since that is all
                         * that will be read.
                         */
-                       /* FIXME: parse the header for more correct value */
-                       amount = skb->len - (3+8+8);
+                       amount = skb->len - ieee802154_hdr_length(skb);
                }
                spin_unlock_bh(&sk->sk_receive_queue.lock);
                return put_user(amount, (int __user *)arg);
@@ -181,7 +182,7 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
                goto out;
        }
 
-       memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr));
+       ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr);
 
 out:
        release_sock(sk);
@@ -194,8 +195,8 @@ static int dgram_disconnect(struct sock *sk, int flags)
 
        lock_sock(sk);
 
-       ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
-       memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+       ro->dst_addr.mode = IEEE802154_ADDR_LONG;
+       memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
 
        release_sock(sk);
 
@@ -232,7 +233,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
 
        if (size > mtu) {
                pr_debug("size = %Zu, mtu = %u\n", size, mtu);
-               err = -EINVAL;
+               err = -EMSGSIZE;
                goto out_dev;
        }
 
@@ -312,7 +313,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
 
        if (saddr) {
                saddr->family = AF_IEEE802154;
-               saddr->addr = mac_cb(skb)->sa;
+               ieee802154_addr_to_sa(&saddr->addr, &mac_cb(skb)->source);
                *addr_len = sizeof(*saddr);
        }
 
@@ -336,40 +337,43 @@ static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
        return NET_RX_SUCCESS;
 }
 
-static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id,
-               u16 short_addr, struct dgram_sock *ro)
+static inline bool
+ieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr,
+                     struct dgram_sock *ro)
 {
        if (!ro->bound)
-               return 1;
+               return true;
 
-       if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG &&
-           !memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN))
-               return 1;
+       if (ro->src_addr.mode == IEEE802154_ADDR_LONG &&
+           hw_addr == ro->src_addr.extended_addr)
+               return true;
 
-       if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT &&
-                    pan_id == ro->src_addr.pan_id &&
-                    short_addr == ro->src_addr.short_addr)
-               return 1;
+       if (ro->src_addr.mode == IEEE802154_ADDR_SHORT &&
+           pan_id == ro->src_addr.pan_id &&
+           short_addr == ro->src_addr.short_addr)
+               return true;
 
-       return 0;
+       return false;
 }
 
 int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
 {
        struct sock *sk, *prev = NULL;
        int ret = NET_RX_SUCCESS;
-       u16 pan_id, short_addr;
+       __le16 pan_id, short_addr;
+       __le64 hw_addr;
 
        /* Data frame processing */
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
        pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
        short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
+       hw_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
 
        read_lock(&dgram_lock);
        sk_for_each(sk, &dgram_head) {
-               if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr,
-                                       dgram_sk(sk))) {
+               if (ieee802154_match_sock(hw_addr, pan_id, short_addr,
+                                         dgram_sk(sk))) {
                        if (prev) {
                                struct sk_buff *clone;
                                clone = skb_clone(skb, GFP_ATOMIC);
diff --git a/net/ieee802154/header_ops.c b/net/ieee802154/header_ops.c
new file mode 100644 (file)
index 0000000..bed42a4
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2014 Fraunhofer ITWM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
+ */
+
+#include <net/mac802154.h>
+#include <net/ieee802154.h>
+#include <net/ieee802154_netdev.h>
+
+static int
+ieee802154_hdr_push_addr(u8 *buf, const struct ieee802154_addr *addr,
+                        bool omit_pan)
+{
+       int pos = 0;
+
+       if (addr->mode == IEEE802154_ADDR_NONE)
+               return 0;
+
+       if (!omit_pan) {
+               memcpy(buf + pos, &addr->pan_id, 2);
+               pos += 2;
+       }
+
+       switch (addr->mode) {
+       case IEEE802154_ADDR_SHORT:
+               memcpy(buf + pos, &addr->short_addr, 2);
+               pos += 2;
+               break;
+
+       case IEEE802154_ADDR_LONG:
+               memcpy(buf + pos, &addr->extended_addr, IEEE802154_ADDR_LEN);
+               pos += IEEE802154_ADDR_LEN;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return pos;
+}
+
+static int
+ieee802154_hdr_push_sechdr(u8 *buf, const struct ieee802154_sechdr *hdr)
+{
+       int pos = 5;
+
+       memcpy(buf, hdr, 1);
+       memcpy(buf + 1, &hdr->frame_counter, 4);
+
+       switch (hdr->key_id_mode) {
+       case IEEE802154_SCF_KEY_IMPLICIT:
+               return pos;
+
+       case IEEE802154_SCF_KEY_INDEX:
+               break;
+
+       case IEEE802154_SCF_KEY_SHORT_INDEX:
+               memcpy(buf + pos, &hdr->short_src, 4);
+               pos += 4;
+               break;
+
+       case IEEE802154_SCF_KEY_HW_INDEX:
+               memcpy(buf + pos, &hdr->extended_src, IEEE802154_ADDR_LEN);
+               pos += IEEE802154_ADDR_LEN;
+               break;
+       }
+
+       buf[pos++] = hdr->key_id;
+
+       return pos;
+}
+
+int
+ieee802154_hdr_push(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
+{
+       u8 buf[MAC802154_FRAME_HARD_HEADER_LEN];
+       int pos = 2;
+       int rc;
+       struct ieee802154_hdr_fc fc = hdr->fc;
+
+       buf[pos++] = hdr->seq;
+
+       fc.dest_addr_mode = hdr->dest.mode;
+
+       rc = ieee802154_hdr_push_addr(buf + pos, &hdr->dest, false);
+       if (rc < 0)
+               return -EINVAL;
+       pos += rc;
+
+       fc.source_addr_mode = hdr->source.mode;
+
+       if (hdr->source.pan_id == hdr->dest.pan_id &&
+           hdr->dest.mode != IEEE802154_ADDR_NONE)
+               fc.intra_pan = true;
+
+       rc = ieee802154_hdr_push_addr(buf + pos, &hdr->source, fc.intra_pan);
+       if (rc < 0)
+               return -EINVAL;
+       pos += rc;
+
+       if (fc.security_enabled) {
+               fc.version = 1;
+
+               rc = ieee802154_hdr_push_sechdr(buf + pos, &hdr->sec);
+               if (rc < 0)
+                       return -EINVAL;
+
+               pos += rc;
+       }
+
+       memcpy(buf, &fc, 2);
+
+       memcpy(skb_push(skb, pos), buf, pos);
+
+       return pos;
+}
+EXPORT_SYMBOL_GPL(ieee802154_hdr_push);
+
+static int
+ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan,
+                       struct ieee802154_addr *addr)
+{
+       int pos = 0;
+
+       addr->mode = mode;
+
+       if (mode == IEEE802154_ADDR_NONE)
+               return 0;
+
+       if (!omit_pan) {
+               memcpy(&addr->pan_id, buf + pos, 2);
+               pos += 2;
+       }
+
+       if (mode == IEEE802154_ADDR_SHORT) {
+               memcpy(&addr->short_addr, buf + pos, 2);
+               return pos + 2;
+       } else {
+               memcpy(&addr->extended_addr, buf + pos, IEEE802154_ADDR_LEN);
+               return pos + IEEE802154_ADDR_LEN;
+       }
+}
+
+static int ieee802154_hdr_addr_len(int mode, bool omit_pan)
+{
+       int pan_len = omit_pan ? 0 : 2;
+
+       switch (mode) {
+       case IEEE802154_ADDR_NONE: return 0;
+       case IEEE802154_ADDR_SHORT: return 2 + pan_len;
+       case IEEE802154_ADDR_LONG: return IEEE802154_ADDR_LEN + pan_len;
+       default: return -EINVAL;
+       }
+}
+
+static int
+ieee802154_hdr_get_sechdr(const u8 *buf, struct ieee802154_sechdr *hdr)
+{
+       int pos = 5;
+
+       memcpy(hdr, buf, 1);
+       memcpy(&hdr->frame_counter, buf + 1, 4);
+
+       switch (hdr->key_id_mode) {
+       case IEEE802154_SCF_KEY_IMPLICIT:
+               return pos;
+
+       case IEEE802154_SCF_KEY_INDEX:
+               break;
+
+       case IEEE802154_SCF_KEY_SHORT_INDEX:
+               memcpy(&hdr->short_src, buf + pos, 4);
+               pos += 4;
+               break;
+
+       case IEEE802154_SCF_KEY_HW_INDEX:
+               memcpy(&hdr->extended_src, buf + pos, IEEE802154_ADDR_LEN);
+               pos += IEEE802154_ADDR_LEN;
+               break;
+       }
+
+       hdr->key_id = buf[pos++];
+
+       return pos;
+}
+
+static int ieee802154_hdr_sechdr_len(u8 sc)
+{
+       switch (IEEE802154_SCF_KEY_ID_MODE(sc)) {
+       case IEEE802154_SCF_KEY_IMPLICIT: return 5;
+       case IEEE802154_SCF_KEY_INDEX: return 6;
+       case IEEE802154_SCF_KEY_SHORT_INDEX: return 10;
+       case IEEE802154_SCF_KEY_HW_INDEX: return 14;
+       default: return -EINVAL;
+       }
+}
+
+static int ieee802154_hdr_minlen(const struct ieee802154_hdr *hdr)
+{
+       int dlen, slen;
+
+       dlen = ieee802154_hdr_addr_len(hdr->fc.dest_addr_mode, false);
+       slen = ieee802154_hdr_addr_len(hdr->fc.source_addr_mode,
+                                      hdr->fc.intra_pan);
+
+       if (slen < 0 || dlen < 0)
+               return -EINVAL;
+
+       return 3 + dlen + slen + hdr->fc.security_enabled;
+}
+
+static int
+ieee802154_hdr_get_addrs(const u8 *buf, struct ieee802154_hdr *hdr)
+{
+       int pos = 0;
+
+       pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.dest_addr_mode,
+                                      false, &hdr->dest);
+       pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.source_addr_mode,
+                                      hdr->fc.intra_pan, &hdr->source);
+
+       if (hdr->fc.intra_pan)
+               hdr->source.pan_id = hdr->dest.pan_id;
+
+       return pos;
+}
+
+int
+ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr)
+{
+       int pos = 3, rc;
+
+       if (!pskb_may_pull(skb, 3))
+               return -EINVAL;
+
+       memcpy(hdr, skb->data, 3);
+
+       rc = ieee802154_hdr_minlen(hdr);
+       if (rc < 0 || !pskb_may_pull(skb, rc))
+               return -EINVAL;
+
+       pos += ieee802154_hdr_get_addrs(skb->data + pos, hdr);
+
+       if (hdr->fc.security_enabled) {
+               int want = pos + ieee802154_hdr_sechdr_len(skb->data[pos]);
+
+               if (!pskb_may_pull(skb, want))
+                       return -EINVAL;
+
+               pos += ieee802154_hdr_get_sechdr(skb->data + pos, &hdr->sec);
+       }
+
+       skb_pull(skb, pos);
+       return pos;
+}
+EXPORT_SYMBOL_GPL(ieee802154_hdr_pull);
+
+int
+ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
+{
+       const u8 *buf = skb_mac_header(skb);
+       int pos = 3, rc;
+
+       if (buf + 3 > skb_tail_pointer(skb))
+               return -EINVAL;
+
+       memcpy(hdr, buf, 3);
+
+       rc = ieee802154_hdr_minlen(hdr);
+       if (rc < 0 || buf + rc > skb_tail_pointer(skb))
+               return -EINVAL;
+
+       pos += ieee802154_hdr_get_addrs(buf + pos, hdr);
+       return pos;
+}
+EXPORT_SYMBOL_GPL(ieee802154_hdr_peek_addrs);
index ba5c1e002f37b2630c53a0284736f5d177bded76..bda8dba4f993b0ce981888627cd3099dc2f13642 100644 (file)
 
 #include "ieee802154.h"
 
+static int nla_put_hwaddr(struct sk_buff *msg, int type, __le64 hwaddr)
+{
+       return nla_put_u64(msg, type, swab64((__force u64)hwaddr));
+}
+
+static __le64 nla_get_hwaddr(const struct nlattr *nla)
+{
+       return ieee802154_devaddr_from_raw(nla_data(nla));
+}
+
+static int nla_put_shortaddr(struct sk_buff *msg, int type, __le16 addr)
+{
+       return nla_put_u16(msg, type, le16_to_cpu(addr));
+}
+
+static __le16 nla_get_shortaddr(const struct nlattr *nla)
+{
+       return cpu_to_le16(nla_get_u16(nla));
+}
+
 int ieee802154_nl_assoc_indic(struct net_device *dev,
                struct ieee802154_addr *addr, u8 cap)
 {
@@ -46,7 +66,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
 
        pr_debug("%s\n", __func__);
 
-       if (addr->addr_type != IEEE802154_ADDR_LONG) {
+       if (addr->mode != IEEE802154_ADDR_LONG) {
                pr_err("%s: received non-long source address!\n", __func__);
                return -EINVAL;
        }
@@ -59,8 +79,8 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr) ||
-           nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
-                   addr->hwaddr) ||
+           nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
+                          addr->extended_addr) ||
            nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
                goto nla_put_failure;
 
@@ -72,7 +92,7 @@ nla_put_failure:
 }
 EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
 
-int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
+int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr,
                u8 status)
 {
        struct sk_buff *msg;
@@ -87,7 +107,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr) ||
-           nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
+           nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
            nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
                goto nla_put_failure;
        return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
@@ -114,13 +134,13 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev,
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr))
                goto nla_put_failure;
-       if (addr->addr_type == IEEE802154_ADDR_LONG) {
-               if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
-                           addr->hwaddr))
+       if (addr->mode == IEEE802154_ADDR_LONG) {
+               if (nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
+                                  addr->extended_addr))
                        goto nla_put_failure;
        } else {
-               if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
-                               addr->short_addr))
+               if (nla_put_shortaddr(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
+                                     addr->short_addr))
                        goto nla_put_failure;
        }
        if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
@@ -157,8 +177,8 @@ nla_put_failure:
 }
 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
 
-int ieee802154_nl_beacon_indic(struct net_device *dev,
-               u16 panid, u16 coord_addr)
+int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
+                              __le16 coord_addr)
 {
        struct sk_buff *msg;
 
@@ -172,8 +192,9 @@ int ieee802154_nl_beacon_indic(struct net_device *dev,
            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr) ||
-           nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) ||
-           nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
+           nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_SHORT_ADDR,
+                             coord_addr) ||
+           nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
                goto nla_put_failure;
        return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
 
@@ -243,6 +264,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
 {
        void *hdr;
        struct wpan_phy *phy;
+       __le16 short_addr, pan_id;
 
        pr_debug("%s\n", __func__);
 
@@ -254,15 +276,16 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
        phy = ieee802154_mlme_ops(dev)->get_phy(dev);
        BUG_ON(!phy);
 
+       short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
+       pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+
        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
            nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr) ||
-           nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR,
-                       ieee802154_mlme_ops(dev)->get_short_addr(dev)) ||
-           nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
-                       ieee802154_mlme_ops(dev)->get_pan_id(dev)))
+           nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
+           nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, pan_id))
                goto nla_put_failure;
        wpan_phy_put(phy);
        return genlmsg_end(msg, hdr);
@@ -322,16 +345,16 @@ int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
                goto out;
 
        if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
-               addr.addr_type = IEEE802154_ADDR_LONG;
-               nla_memcpy(addr.hwaddr,
-                               info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
-                               IEEE802154_ADDR_LEN);
+               addr.mode = IEEE802154_ADDR_LONG;
+               addr.extended_addr = nla_get_hwaddr(
+                               info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]);
        } else {
-               addr.addr_type = IEEE802154_ADDR_SHORT;
-               addr.short_addr = nla_get_u16(
+               addr.mode = IEEE802154_ADDR_SHORT;
+               addr.short_addr = nla_get_shortaddr(
                                info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
        }
-       addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+       addr.pan_id = nla_get_shortaddr(
+                       info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
 
        if (info->attrs[IEEE802154_ATTR_PAGE])
                page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
@@ -365,14 +388,13 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
        if (!ieee802154_mlme_ops(dev)->assoc_resp)
                goto out;
 
-       addr.addr_type = IEEE802154_ADDR_LONG;
-       nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
-                       IEEE802154_ADDR_LEN);
+       addr.mode = IEEE802154_ADDR_LONG;
+       addr.extended_addr = nla_get_hwaddr(
+                       info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
        addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 
-
        ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
-               nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
+               nla_get_shortaddr(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
                nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
 
 out:
@@ -398,13 +420,12 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
                goto out;
 
        if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
-               addr.addr_type = IEEE802154_ADDR_LONG;
-               nla_memcpy(addr.hwaddr,
-                               info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
-                               IEEE802154_ADDR_LEN);
+               addr.mode = IEEE802154_ADDR_LONG;
+               addr.extended_addr = nla_get_hwaddr(
+                               info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
        } else {
-               addr.addr_type = IEEE802154_ADDR_SHORT;
-               addr.short_addr = nla_get_u16(
+               addr.mode = IEEE802154_ADDR_SHORT;
+               addr.short_addr = nla_get_shortaddr(
                                info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
        }
        addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
@@ -449,10 +470,11 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
        if (!ieee802154_mlme_ops(dev)->start_req)
                goto out;
 
-       addr.addr_type = IEEE802154_ADDR_SHORT;
-       addr.short_addr = nla_get_u16(
+       addr.mode = IEEE802154_ADDR_SHORT;
+       addr.short_addr = nla_get_shortaddr(
                        info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
-       addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+       addr.pan_id = nla_get_shortaddr(
+                       info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
 
        channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
        bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
@@ -467,7 +489,7 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
                page = 0;
 
 
-       if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
+       if (addr.short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
                ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
                dev_put(dev);
                return -EINVAL;
index 41f538b8e59c9d7912cdf51287d9afa7a116c646..e5258cf6773b2270c66ce524f6bbd7646e286c1e 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <net/af_ieee802154.h>
+#include <net/ieee802154_netdev.h>
 
 #include "af802154.h"
 
@@ -55,21 +56,24 @@ static void raw_close(struct sock *sk, long timeout)
        sk_common_release(sk);
 }
 
-static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len)
+static int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len)
 {
-       struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+       struct ieee802154_addr addr;
+       struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr;
        int err = 0;
        struct net_device *dev = NULL;
 
-       if (len < sizeof(*addr))
+       if (len < sizeof(*uaddr))
                return -EINVAL;
 
-       if (addr->family != AF_IEEE802154)
+       uaddr = (struct sockaddr_ieee802154 *)_uaddr;
+       if (uaddr->family != AF_IEEE802154)
                return -EINVAL;
 
        lock_sock(sk);
 
-       dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
+       ieee802154_addr_from_sa(&addr, &uaddr->addr);
+       dev = ieee802154_get_dev(sock_net(sk), &addr);
        if (!dev) {
                err = -ENODEV;
                goto out;
index 4511fc22ef16dca58a0af84ab18c51a599cb40c0..ef2d54372b134330d0fa7c51c2049379ce69e85e 100644 (file)
 #include <linux/export.h>
 
 #include <net/ieee802154_netdev.h>
+#include <net/6lowpan.h>
 #include <net/ipv6.h>
 #include <net/inet_frag.h>
 
-#include "6lowpan.h"
 #include "reassembly.h"
 
+struct lowpan_frag_info {
+       __be16 d_tag;
+       u16 d_size;
+       u8 d_offset;
+};
+
+struct lowpan_frag_info *lowpan_cb(struct sk_buff *skb)
+{
+       return (struct lowpan_frag_info *)skb->cb;
+}
+
 static struct inet_frags lowpan_frags;
 
 static int lowpan_frag_reasm(struct lowpan_frag_queue *fq,
@@ -58,19 +69,18 @@ static unsigned int lowpan_hashfn(struct inet_frag_queue *q)
        return lowpan_hash_frag(fq->tag, fq->d_size, &fq->saddr, &fq->daddr);
 }
 
-bool lowpan_frag_match(struct inet_frag_queue *q, void *a)
+static bool lowpan_frag_match(struct inet_frag_queue *q, void *a)
 {
        struct lowpan_frag_queue *fq;
        struct lowpan_create_arg *arg = a;
 
        fq = container_of(q, struct lowpan_frag_queue, q);
        return  fq->tag == arg->tag && fq->d_size == arg->d_size &&
-               ieee802154_addr_addr_equal(&fq->saddr, arg->src) &&
-               ieee802154_addr_addr_equal(&fq->daddr, arg->dst);
+               ieee802154_addr_equal(&fq->saddr, arg->src) &&
+               ieee802154_addr_equal(&fq->daddr, arg->dst);
 }
-EXPORT_SYMBOL(lowpan_frag_match);
 
-void lowpan_frag_init(struct inet_frag_queue *q, void *a)
+static void lowpan_frag_init(struct inet_frag_queue *q, void *a)
 {
        struct lowpan_frag_queue *fq;
        struct lowpan_create_arg *arg = a;
@@ -82,21 +92,6 @@ void lowpan_frag_init(struct inet_frag_queue *q, void *a)
        fq->saddr = *arg->src;
        fq->daddr = *arg->dst;
 }
-EXPORT_SYMBOL(lowpan_frag_init);
-
-void lowpan_expire_frag_queue(struct frag_queue *fq, struct inet_frags *frags)
-{
-       spin_lock(&fq->q.lock);
-
-       if (fq->q.last_in & INET_FRAG_COMPLETE)
-               goto out;
-
-       inet_frag_kill(&fq->q, frags);
-out:
-       spin_unlock(&fq->q.lock);
-       inet_frag_put(&fq->q, frags);
-}
-EXPORT_SYMBOL(lowpan_expire_frag_queue);
 
 static void lowpan_frag_expire(unsigned long data)
 {
@@ -106,12 +101,21 @@ static void lowpan_frag_expire(unsigned long data)
        fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q);
        net = container_of(fq->q.net, struct net, ieee802154_lowpan.frags);
 
-       lowpan_expire_frag_queue(fq, &lowpan_frags);
+       spin_lock(&fq->q.lock);
+
+       if (fq->q.last_in & INET_FRAG_COMPLETE)
+               goto out;
+
+       inet_frag_kill(&fq->q, &lowpan_frags);
+out:
+       spin_unlock(&fq->q.lock);
+       inet_frag_put(&fq->q, &lowpan_frags);
 }
 
 static inline struct lowpan_frag_queue *
-fq_find(struct net *net, const struct ieee802154_frag_info *frag_info,
-       const struct ieee802154_addr *src, const struct ieee802154_addr *dst)
+fq_find(struct net *net, const struct lowpan_frag_info *frag_info,
+       const struct ieee802154_addr *src,
+       const struct ieee802154_addr *dst)
 {
        struct inet_frag_queue *q;
        struct lowpan_create_arg arg;
@@ -144,8 +148,8 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
        if (fq->q.last_in & INET_FRAG_COMPLETE)
                goto err;
 
-       offset = mac_cb(skb)->frag_info.d_offset << 3;
-       end = mac_cb(skb)->frag_info.d_size;
+       offset = lowpan_cb(skb)->d_offset << 3;
+       end = lowpan_cb(skb)->d_size;
 
        /* Is this the final fragment? */
        if (offset + skb->len == end) {
@@ -171,15 +175,13 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
         * this fragment, right?
         */
        prev = fq->q.fragments_tail;
-       if (!prev || mac_cb(prev)->frag_info.d_offset <
-                    mac_cb(skb)->frag_info.d_offset) {
+       if (!prev || lowpan_cb(prev)->d_offset < lowpan_cb(skb)->d_offset) {
                next = NULL;
                goto found;
        }
        prev = NULL;
        for (next = fq->q.fragments; next != NULL; next = next->next) {
-               if (mac_cb(next)->frag_info.d_offset >=
-                   mac_cb(skb)->frag_info.d_offset)
+               if (lowpan_cb(next)->d_offset >= lowpan_cb(skb)->d_offset)
                        break;  /* bingo! */
                prev = next;
        }
@@ -326,7 +328,7 @@ out_oom:
 }
 
 static int lowpan_get_frag_info(struct sk_buff *skb, const u8 frag_type,
-                               struct ieee802154_frag_info *frag_info)
+                               struct lowpan_frag_info *frag_info)
 {
        bool fail;
        u8 pattern = 0, low = 0;
@@ -353,9 +355,13 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
 {
        struct lowpan_frag_queue *fq;
        struct net *net = dev_net(skb->dev);
-       struct ieee802154_frag_info *frag_info = &mac_cb(skb)->frag_info;
+       struct lowpan_frag_info *frag_info = lowpan_cb(skb);
+       struct ieee802154_addr source, dest;
        int err;
 
+       source = mac_cb(skb)->source;
+       dest = mac_cb(skb)->dest;
+
        err = lowpan_get_frag_info(skb, frag_type, frag_info);
        if (err < 0)
                goto err;
@@ -365,7 +371,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
 
        inet_frag_evictor(&net->ieee802154_lowpan.frags, &lowpan_frags, false);
 
-       fq = fq_find(net, frag_info, &mac_cb(skb)->sa, &mac_cb(skb)->da);
+       fq = fq_find(net, frag_info, &source, &dest);
        if (fq != NULL) {
                int ret;
                spin_lock(&fq->q.lock);
@@ -441,7 +447,7 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
                table[0].data = &net->ieee802154_lowpan.frags.high_thresh;
                table[1].data = &net->ieee802154_lowpan.frags.low_thresh;
                table[2].data = &net->ieee802154_lowpan.frags.timeout;
-               table[2].data = &net->ieee802154_lowpan.max_dsize;
+               table[3].data = &net->ieee802154_lowpan.max_dsize;
 
                /* Don't export sysctls to unprivileged users */
                if (net->user_ns != &init_user_ns)
@@ -535,7 +541,7 @@ int __init lowpan_net_frag_init(void)
 
        ret = lowpan_frags_sysctl_register();
        if (ret)
-               goto out;
+               return ret;
 
        ret = register_pernet_subsys(&lowpan_frags_ops);
        if (ret)
@@ -550,9 +556,10 @@ int __init lowpan_net_frag_init(void)
        lowpan_frags.frag_expire = lowpan_frag_expire;
        lowpan_frags.secret_interval = 10 * 60 * HZ;
        inet_frags_init(&lowpan_frags);
+
+       return ret;
 err_pernet:
        lowpan_frags_sysctl_unregister();
-out:
        return ret;
 }
 
index 055518b9da2d4425bc7bbcb63c2bd88c6e8d4500..74e4a7c98191109cadf7ae029c7f42602630cbc7 100644 (file)
@@ -23,10 +23,10 @@ struct lowpan_frag_queue {
 
 static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
 {
-       switch (a->addr_type) {
+       switch (a->mode) {
        case IEEE802154_ADDR_LONG:
-               return (__force u32)((((u32 *)a->hwaddr))[0] ^
-                                     ((u32 *)(a->hwaddr))[1]);
+               return (((__force u64)a->extended_addr) >> 32) ^
+                       (((__force u64)a->extended_addr) & 0xffffffff);
        case IEEE802154_ADDR_SHORT:
                return (__force u32)(a->short_addr);
        default:
@@ -34,31 +34,6 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
        }
 }
 
-static inline bool ieee802154_addr_addr_equal(const struct ieee802154_addr *a1,
-                                  const struct ieee802154_addr *a2)
-{
-       if (a1->pan_id != a2->pan_id)
-               return false;
-
-       if (a1->addr_type != a2->addr_type)
-               return false;
-
-       switch (a1->addr_type) {
-       case IEEE802154_ADDR_LONG:
-               if (memcmp(a1->hwaddr, a2->hwaddr, IEEE802154_ADDR_LEN))
-                       return false;
-               break;
-       case IEEE802154_ADDR_SHORT:
-               if (a1->short_addr != a2->short_addr)
-                       return false;
-               break;
-       default:
-               return false;
-       }
-
-       return true;
-}
-
 int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type);
 void lowpan_net_frag_exit(void);
 int lowpan_net_frag_init(void);
index ecd2c3f245ce2b2e0b79f17417c5e6ad8c70abf6..8c54870db792cab059bff464d29776510ec3e5ec 100644 (file)
@@ -1296,8 +1296,11 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
 
        segs = ERR_PTR(-EPROTONOSUPPORT);
 
-       /* Note : following gso_segment() might change skb->encapsulation */
-       udpfrag = !skb->encapsulation && proto == IPPROTO_UDP;
+       if (skb->encapsulation &&
+           skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))
+               udpfrag = proto == IPPROTO_UDP && encap;
+       else
+               udpfrag = proto == IPPROTO_UDP && !skb->encapsulation;
 
        ops = rcu_dereference(inet_offloads[proto]);
        if (likely(ops && ops->callbacks.gso_segment))
@@ -1502,9 +1505,9 @@ u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset)
                bhptr = per_cpu_ptr(mib[0], cpu);
                syncp = (struct u64_stats_sync *)(bhptr + syncp_offset);
                do {
-                       start = u64_stats_fetch_begin_bh(syncp);
+                       start = u64_stats_fetch_begin_irq(syncp);
                        v = *(((u64 *) bhptr) + offt);
-               } while (u64_stats_fetch_retry_bh(syncp, start));
+               } while (u64_stats_fetch_retry_irq(syncp, start));
 
                res += v;
        }
index bb075fc9a14f25169c175c7fcdcb86d56c709627..3b01959bf4bb0bbc208d8d564c8595c67eedd179 100644 (file)
@@ -208,7 +208,7 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force)
        }
 
        work = frag_mem_limit(nf) - nf->low_thresh;
-       while (work > 0) {
+       while (work > 0 || force) {
                spin_lock(&nf->lru_lock);
 
                if (list_empty(&nf->lru_list)) {
@@ -278,9 +278,10 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
 
        atomic_inc(&qp->refcnt);
        hlist_add_head(&qp->list, &hb->chain);
+       inet_frag_lru_add(nf, qp);
        spin_unlock(&hb->chain_lock);
        read_unlock(&f->lock);
-       inet_frag_lru_add(nf, qp);
+
        return qp;
 }
 
index e85445b2b10258b729ae37eda516b290a06b8cd4..1a0755fea4914c20f95d036f30638ea2677b764f 100644 (file)
@@ -422,9 +422,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->tc_index = from->tc_index;
 #endif
        nf_copy(to, from);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-       to->nf_trace = from->nf_trace;
-#endif
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
        to->ipvs_property = from->ipvs_property;
 #endif
index 4fff64418fb2ebfcf47b4d521b801d0fc23eb074..66aaf506fbef8bf19baaa9e2f5ebd6e12c76e40e 100644 (file)
@@ -93,13 +93,14 @@ static void tunnel_dst_reset(struct ip_tunnel *t)
        tunnel_dst_set(t, NULL);
 }
 
-static void tunnel_dst_reset_all(struct ip_tunnel *t)
+void ip_tunnel_dst_reset_all(struct ip_tunnel *t)
 {
        int i;
 
        for_each_possible_cpu(i)
                __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL);
 }
+EXPORT_SYMBOL(ip_tunnel_dst_reset_all);
 
 static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie)
 {
@@ -119,52 +120,6 @@ static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie)
        return (struct rtable *)dst;
 }
 
-/* Often modified stats are per cpu, other are shared (netdev->stats) */
-struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
-                                               struct rtnl_link_stats64 *tot)
-{
-       int i;
-
-       for_each_possible_cpu(i) {
-               const struct pcpu_sw_netstats *tstats =
-                                                  per_cpu_ptr(dev->tstats, i);
-               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
-               unsigned int start;
-
-               do {
-                       start = u64_stats_fetch_begin_bh(&tstats->syncp);
-                       rx_packets = tstats->rx_packets;
-                       tx_packets = tstats->tx_packets;
-                       rx_bytes = tstats->rx_bytes;
-                       tx_bytes = tstats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
-
-               tot->rx_packets += rx_packets;
-               tot->tx_packets += tx_packets;
-               tot->rx_bytes   += rx_bytes;
-               tot->tx_bytes   += tx_bytes;
-       }
-
-       tot->multicast = dev->stats.multicast;
-
-       tot->rx_crc_errors = dev->stats.rx_crc_errors;
-       tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
-       tot->rx_length_errors = dev->stats.rx_length_errors;
-       tot->rx_frame_errors = dev->stats.rx_frame_errors;
-       tot->rx_errors = dev->stats.rx_errors;
-
-       tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
-       tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
-       tot->tx_dropped = dev->stats.tx_dropped;
-       tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
-       tot->tx_errors = dev->stats.tx_errors;
-
-       tot->collisions  = dev->stats.collisions;
-
-       return tot;
-}
-EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
-
 static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p,
                                __be16 flags, __be32 key)
 {
@@ -763,7 +718,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
                if (set_mtu)
                        dev->mtu = mtu;
        }
-       tunnel_dst_reset_all(t);
+       ip_tunnel_dst_reset_all(t);
        netdev_state_change(dev);
 }
 
@@ -1091,7 +1046,7 @@ void ip_tunnel_uninit(struct net_device *dev)
        if (itn->fb_tunnel_dev != dev)
                ip_tunnel_del(netdev_priv(dev));
 
-       tunnel_dst_reset_all(tunnel);
+       ip_tunnel_dst_reset_all(tunnel);
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_uninit);
 
index 6156f4ef5e919ccdc470f8cdb5a27593dedbe2c3..b86f0a37fa7cc425c5b52540da03e966e3c0e92e 100644 (file)
@@ -108,7 +108,6 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
        nf_reset(skb);
        secpath_reset(skb);
        skb_clear_hash_if_not_l4(skb);
-       skb_dst_drop(skb);
        skb->vlan_tci = 0;
        skb_set_queue_mapping(skb, 0);
        skb->pkt_type = PACKET_HOST;
@@ -148,3 +147,49 @@ error:
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(iptunnel_handle_offloads);
+
+/* Often modified stats are per cpu, other are shared (netdev->stats) */
+struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
+                                               struct rtnl_link_stats64 *tot)
+{
+       int i;
+
+       for_each_possible_cpu(i) {
+               const struct pcpu_sw_netstats *tstats =
+                                                  per_cpu_ptr(dev->tstats, i);
+               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+               unsigned int start;
+
+               do {
+                       start = u64_stats_fetch_begin_irq(&tstats->syncp);
+                       rx_packets = tstats->rx_packets;
+                       tx_packets = tstats->tx_packets;
+                       rx_bytes = tstats->rx_bytes;
+                       tx_bytes = tstats->tx_bytes;
+               } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
+
+               tot->rx_packets += rx_packets;
+               tot->tx_packets += tx_packets;
+               tot->rx_bytes   += rx_bytes;
+               tot->tx_bytes   += tx_bytes;
+       }
+
+       tot->multicast = dev->stats.multicast;
+
+       tot->rx_crc_errors = dev->stats.rx_crc_errors;
+       tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
+       tot->rx_length_errors = dev->stats.rx_length_errors;
+       tot->rx_frame_errors = dev->stats.rx_frame_errors;
+       tot->rx_errors = dev->stats.rx_errors;
+
+       tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
+       tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
+       tot->tx_dropped = dev->stats.tx_dropped;
+       tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
+       tot->tx_errors = dev->stats.tx_errors;
+
+       tot->collisions  = dev->stats.collisions;
+
+       return tot;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
index c3e0adea9c277585f01dff2f1740787bb3d19a66..7ebd6e37875cc95b08d294ff64306925d05e550e 100644 (file)
@@ -61,7 +61,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
                skb_dst_set(skb, NULL);
                dst = xfrm_lookup(net, dst, flowi4_to_flowi(&fl4), skb->sk, 0);
                if (IS_ERR(dst))
-                       return PTR_ERR(dst);;
+                       return PTR_ERR(dst);
                skb_dst_set(skb, dst);
        }
 #endif
index d551e31b416e02e728a433293d25317e9c930dcb..7c676671329d9432eb2392f6b4fc649ebcdae97f 100644 (file)
@@ -1198,8 +1198,8 @@ static int snmp_translate(struct nf_conn *ct,
                map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip);
        } else {
                /* DNAT replies */
-               map.from = NOCT1(&ct->tuplehash[dir].tuple.src.u3.ip);
-               map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip);
+               map.from = NOCT1(&ct->tuplehash[!dir].tuple.src.u3.ip);
+               map.to = NOCT1(&ct->tuplehash[dir].tuple.dst.u3.ip);
        }
 
        if (map.from == map.to)
index 7374905b3701ba13bb139941e7bf3e87571a7c14..4bd6d52eeffb6c7ddc3e98054a7070826a4c4dcd 100644 (file)
@@ -1044,7 +1044,8 @@ void tcp_free_fastopen_req(struct tcp_sock *tp)
        }
 }
 
-static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size)
+static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
+                               int *copied, size_t size)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int err, flags;
@@ -1059,11 +1060,12 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size)
        if (unlikely(tp->fastopen_req == NULL))
                return -ENOBUFS;
        tp->fastopen_req->data = msg;
+       tp->fastopen_req->size = size;
 
        flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
        err = __inet_stream_connect(sk->sk_socket, msg->msg_name,
                                    msg->msg_namelen, flags);
-       *size = tp->fastopen_req->copied;
+       *copied = tp->fastopen_req->copied;
        tcp_free_fastopen_req(tp);
        return err;
 }
@@ -1083,7 +1085,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        flags = msg->msg_flags;
        if (flags & MSG_FASTOPEN) {
-               err = tcp_sendmsg_fastopen(sk, msg, &copied_syn);
+               err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
                if (err == -EINPROGRESS && copied_syn > 0)
                        goto out;
                else if (err)
index f49351edf97d144e67597d87752c5dc67b5a407c..2b9464c93b8859fcbef0f900f70a4bed2dc6e617 100644 (file)
@@ -290,8 +290,7 @@ bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
        left = tp->snd_cwnd - in_flight;
        if (sk_can_gso(sk) &&
            left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
-           left * tp->mss_cache < sk->sk_gso_max_size &&
-           left < sk->sk_gso_max_segs)
+           left < tp->xmit_size_goal_segs)
                return true;
        return left <= tcp_max_tso_deferred_mss(tp);
 }
index 6e4809389cbf766643e2cb62f78e7dcb7c52809b..e1661f46fd19fb588555e9f769b9eed2c02fd27d 100644 (file)
@@ -1944,8 +1944,9 @@ void tcp_enter_loss(struct sock *sk, int how)
                if (skb == tcp_send_head(sk))
                        break;
 
-               if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
+               if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
                        tp->undo_marker = 0;
+
                TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED;
                if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) {
                        TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
@@ -3066,6 +3067,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                        flag |= FLAG_RETRANS_DATA_ACKED;
                } else {
                        last_ackt = skb->skb_mstamp;
+                       WARN_ON_ONCE(last_ackt.v64 == 0);
                        if (!first_ackt.v64)
                                first_ackt = last_ackt;
 
index aaa68f5b105586156431ce0c9ce0ac3ec2759c9b..e0a7b33fe953c2586ef12fb3e68f1dc592ab600d 100644 (file)
@@ -87,8 +87,8 @@ static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb)
                tcp_rearm_rto(sk);
        }
 
-       NET_ADD_STATS_BH(sock_net(sk), LINUX_MIB_TCPORIGDATASENT,
-                        tcp_skb_pcount(skb));
+       NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPORIGDATASENT,
+                     tcp_skb_pcount(skb));
 }
 
 /* SND.NXT, if window was not shrunk.
@@ -780,6 +780,17 @@ void tcp_release_cb(struct sock *sk)
        if (flags & (1UL << TCP_TSQ_DEFERRED))
                tcp_tsq_handler(sk);
 
+       /* Here begins the tricky part :
+        * We are called from release_sock() with :
+        * 1) BH disabled
+        * 2) sk_lock.slock spinlock held
+        * 3) socket owned by us (sk->sk_lock.owned == 1)
+        *
+        * But following code is meant to be called from BH handlers,
+        * so we should keep BH disabled, but early release socket ownership
+        */
+       sock_release_ownership(sk);
+
        if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) {
                tcp_write_timer_handler(sk);
                __sock_put(sk);
@@ -873,8 +884,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
 
                if (unlikely(skb->fclone == SKB_FCLONE_ORIG &&
                             fclone->fclone == SKB_FCLONE_CLONE))
-                       NET_INC_STATS_BH(sock_net(sk),
-                                        LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
+                       NET_INC_STATS(sock_net(sk),
+                                     LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
 
                if (unlikely(skb_cloned(skb)))
                        skb = pskb_copy(skb, gfp_mask);
@@ -882,6 +893,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                        skb = skb_clone(skb, gfp_mask);
                if (unlikely(!skb))
                        return -ENOBUFS;
+               /* Our usage of tstamp should remain private */
+               skb->tstamp.tv64 = 0;
        }
 
        inet = inet_sk(sk);
@@ -2358,6 +2371,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
        unsigned int cur_mss;
+       int err;
 
        /* Inconslusive MTU probe */
        if (icsk->icsk_mtup.probe_size) {
@@ -2421,11 +2435,15 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                     skb_headroom(skb) >= 0xFFFF)) {
                struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER,
                                                   GFP_ATOMIC);
-               return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
-                             -ENOBUFS;
+               err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
+                            -ENOBUFS;
        } else {
-               return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
+               err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
        }
+
+       if (likely(!err))
+               TCP_SKB_CB(skb)->sacked |= TCPCB_EVER_RETRANS;
+       return err;
 }
 
 int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
@@ -2930,7 +2948,12 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
        space = __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) -
                MAX_TCP_OPTION_SPACE;
 
-       syn_data = skb_copy_expand(syn, skb_headroom(syn), space,
+       space = min_t(size_t, space, fo->size);
+
+       /* limit to order-0 allocations */
+       space = min_t(size_t, space, SKB_MAX_HEAD(MAX_TCP_HEADER));
+
+       syn_data = skb_copy_expand(syn, MAX_TCP_HEADER, space,
                                   sk->sk_allocation);
        if (syn_data == NULL)
                goto fallback;
@@ -2960,6 +2983,12 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
        tcp_connect_queue_skb(sk, data);
        fo->copied = data->len;
 
+       /* syn_data is about to be sent, we need to take current time stamps
+        * for the packets that are in write queue : SYN packet and DATA
+        */
+       skb_mstamp_get(&syn->skb_mstamp);
+       data->skb_mstamp = syn->skb_mstamp;
+
        if (tcp_transmit_skb(sk, syn_data, 0, sk->sk_allocation) == 0) {
                tp->syn_data = (fo->copied > 0);
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPORIGDATASENT);
index d92e5586783e518c1f5db2b1bd3261766ff7a913..438a73aa777cf560f38a87801b03b8ce20a315b1 100644 (file)
@@ -138,6 +138,7 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION
 config IPV6_VTI
 tristate "Virtual (secure) IPv6: tunneling"
        select IPV6_TUNNEL
+       select NET_IP_TUNNEL
        depends on INET6_XFRM_MODE_TUNNEL
        ---help---
        Tunneling means encapsulating data of one protocol type within
index fdbfeca36d6344c22db31886c3661796eb9e8f86..344e972426df847a6f6b87414c37ef29e2ddd127 100644 (file)
@@ -1103,8 +1103,11 @@ retry:
         * Lifetime is greater than REGEN_ADVANCE time units.  In particular,
         * an implementation must not create a temporary address with a zero
         * Preferred Lifetime.
+        * Use age calculation as in addrconf_verify to avoid unnecessary
+        * temporary addresses being generated.
         */
-       if (tmp_prefered_lft <= regen_advance) {
+       age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
+       if (tmp_prefered_lft <= regen_advance + age) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
                ret = -1;
index 140748debc4ade194e5e179636e94264da7e65a1..8af3eb57f4380fd7de7497ff98f40c88f2040e50 100644 (file)
@@ -212,7 +212,7 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
                found = (nexthdr == target);
 
                if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
-                       if (target < 0)
+                       if (target < 0 || found)
                                break;
                        return -ENOENT;
                }
index cf77f3abfd061280f6a211deb4a24bcd247c944a..447a7fbd1bb6f28dc78203ef4f4254705dc68c99 100644 (file)
@@ -25,11 +25,11 @@ int __init ipv6_exthdrs_offload_init(void)
        int ret;
 
        ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
-       if (!ret)
+       if (ret)
                goto out;
 
        ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
-       if (!ret)
+       if (ret)
                goto out_rt;
 
 out:
index 1e8683b135bb7b503d9ab97d5c3c165af2453fa1..59f95affceb0773d052184bdf5fec9f276433d63 100644 (file)
@@ -89,7 +89,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        unsigned int unfrag_ip6hlen;
        u8 *prevhdr;
        int offset = 0;
-       bool tunnel;
+       bool encap, udpfrag;
        int nhoff;
 
        if (unlikely(skb_shinfo(skb)->gso_type &
@@ -110,8 +110,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
                goto out;
 
-       tunnel = SKB_GSO_CB(skb)->encap_level > 0;
-       if (tunnel)
+       encap = SKB_GSO_CB(skb)->encap_level > 0;
+       if (encap)
                features = skb->dev->hw_enc_features & netif_skb_features(skb);
        SKB_GSO_CB(skb)->encap_level += sizeof(*ipv6h);
 
@@ -121,6 +121,12 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
 
        proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
 
+       if (skb->encapsulation &&
+           skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))
+               udpfrag = proto == IPPROTO_UDP && encap;
+       else
+               udpfrag = proto == IPPROTO_UDP && !skb->encapsulation;
+
        ops = rcu_dereference(inet6_offloads[proto]);
        if (likely(ops && ops->callbacks.gso_segment)) {
                skb_reset_transport_header(skb);
@@ -133,13 +139,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        for (skb = segs; skb; skb = skb->next) {
                ipv6h = (struct ipv6hdr *)(skb_mac_header(skb) + nhoff);
                ipv6h->payload_len = htons(skb->len - nhoff - sizeof(*ipv6h));
-               if (tunnel) {
-                       skb_reset_inner_headers(skb);
-                       skb->encapsulation = 1;
-               }
                skb->network_header = (u8 *)ipv6h - skb->head;
 
-               if (!tunnel && proto == IPPROTO_UDP) {
+               if (udpfrag) {
                        unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
                        fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen);
                        fptr->frag_off = htons(offset);
@@ -148,6 +150,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
                        offset += (ntohs(ipv6h->payload_len) -
                                   sizeof(struct frag_hdr));
                }
+               if (encap)
+                       skb_reset_inner_headers(skb);
        }
 
 out:
index be1b7f5a3a5485d8628eafe8f1ec8a3472836e43..90dd551fdd3ce85b89a82832847690838213a19c 100644 (file)
@@ -367,6 +367,9 @@ int ip6_forward(struct sk_buff *skb)
        if (net->ipv6.devconf_all->forwarding == 0)
                goto error;
 
+       if (skb->pkt_type != PACKET_HOST)
+               goto drop;
+
        if (skb_warn_if_lro(skb))
                goto drop;
 
@@ -376,9 +379,6 @@ int ip6_forward(struct sk_buff *skb)
                goto drop;
        }
 
-       if (skb->pkt_type != PACKET_HOST)
-               goto drop;
-
        skb_forward_csum(skb);
 
        /*
@@ -530,9 +530,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->tc_index = from->tc_index;
 #endif
        nf_copy(to, from);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-       to->nf_trace = from->nf_trace;
-#endif
        skb_copy_secmark(to, from);
 }
 
index 8ad59f4811dfb8d4d2216d06b8e00e31fef9a6ed..e1df691d78befcb2bb041244ed3370b44667b40d 100644 (file)
@@ -108,12 +108,12 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
                                                   per_cpu_ptr(dev->tstats, i);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&tstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&tstats->syncp);
                        tmp.rx_packets = tstats->rx_packets;
                        tmp.rx_bytes = tstats->rx_bytes;
                        tmp.tx_packets = tstats->tx_packets;
                        tmp.tx_bytes =  tstats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
 
                sum.rx_packets += tmp.rx_packets;
                sum.rx_bytes   += tmp.rx_bytes;
index 827f795209cf9d607c5a63c188a369bb6c1ad684..d1b35d377e62de73c0fade1d6464e7a3358ba15a 100644 (file)
@@ -13,7 +13,7 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
        int old, new;
 
 #if IS_ENABLED(CONFIG_IPV6)
-       if (rt && !(rt->dst.flags & DST_NOPEER)) {
+       if (rt) {
                struct inet_peer *peer;
                struct net *net;
 
index fb9beb78f00b23fc307384bf6aef21adf2ab6895..587bbdcb22b4c04c0186932d463bce29ca32b38e 100644 (file)
@@ -135,6 +135,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        fl6.flowi6_proto = IPPROTO_ICMPV6;
        fl6.saddr = np->saddr;
        fl6.daddr = *daddr;
+       fl6.flowi6_mark = sk->sk_mark;
        fl6.fl6_icmp_type = user_icmph.icmp6_type;
        fl6.fl6_icmp_code = user_icmph.icmp6_code;
        security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
index 11dac21e658690cdf01d7eb41c7e653d142ad9d4..fba54a407bb2b7c2aae62ac2d03df806bc1a794a 100644 (file)
@@ -1513,7 +1513,7 @@ int ip6_route_add(struct fib6_config *cfg)
        if (!table)
                goto out;
 
-       rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
+       rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
 
        if (!rt) {
                err = -ENOMEM;
index 958027be0e941f50853f865b006ad121aa5025d2..1693c8d885f081e153e115bec78cb2f29a79a6ff 100644 (file)
@@ -475,6 +475,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
                ipip6_tunnel_unlink(sitn, tunnel);
                ipip6_tunnel_del_prl(tunnel, NULL);
        }
+       ip_tunnel_dst_reset_all(tunnel);
        dev_put(dev);
 }
 
@@ -1082,6 +1083,7 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
                t->parms.link = p->link;
                ipip6_tunnel_bind_dev(t->dev);
        }
+       ip_tunnel_dst_reset_all(t);
        netdev_state_change(t->dev);
 }
 
@@ -1112,6 +1114,7 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
        t->ip6rd.relay_prefix = relay_prefix;
        t->ip6rd.prefixlen = ip6rd->prefixlen;
        t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen;
+       ip_tunnel_dst_reset_all(t);
        netdev_state_change(t->dev);
        return 0;
 }
@@ -1271,6 +1274,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
                        err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
                        break;
                }
+               ip_tunnel_dst_reset_all(t);
                netdev_state_change(dev);
                break;
 
@@ -1326,6 +1330,9 @@ static const struct net_device_ops ipip6_netdev_ops = {
 
 static void ipip6_dev_free(struct net_device *dev)
 {
+       struct ip_tunnel *tunnel = netdev_priv(dev);
+
+       free_percpu(tunnel->dst_cache);
        free_percpu(dev->tstats);
        free_netdev(dev);
 }
@@ -1368,6 +1375,12 @@ static int ipip6_tunnel_init(struct net_device *dev)
        if (!dev->tstats)
                return -ENOMEM;
 
+       tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
+       if (!tunnel->dst_cache) {
+               free_percpu(dev->tstats);
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
@@ -1391,6 +1404,12 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
        if (!dev->tstats)
                return -ENOMEM;
 
+       tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
+       if (!tunnel->dst_cache) {
+               free_percpu(dev->tstats);
+               return -ENOMEM;
+       }
+
        dev_hold(dev);
        rcu_assign_pointer(sitn->tunnels_wc[0], tunnel);
        return 0;
index e7359f9eaa8d4dd14b706afc9c7241c85e52d056..b261ee8b83fc87ddabcb447d1235ea8b67429de2 100644 (file)
@@ -113,7 +113,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
                fptr->nexthdr = nexthdr;
                fptr->reserved = 0;
-               ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
+               fptr->identification = skb_shinfo(skb)->ip6_frag_id;
 
                /* Fragment the skb. ipv6 header and the remaining fields of the
                 * fragment header are updated in ipv6_gso_segment()
index e5dc42f0e5279b7d4e19d4a5ab836e525fa24b3c..ab48d4192edd37270c8e666e1bd9be781d249fd1 100644 (file)
@@ -112,7 +112,6 @@ struct l2tp_net {
        spinlock_t l2tp_session_hlist_lock;
 };
 
-static void l2tp_session_set_header_len(struct l2tp_session *session, int version);
 static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
 
 static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
@@ -1131,7 +1130,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
        /* Queue the packet to IP for output */
        skb->local_df = 1;
 #if IS_ENABLED(CONFIG_IPV6)
-       if (skb->sk->sk_family == PF_INET6 && !tunnel->v4mapped)
+       if (tunnel->sock->sk_family == PF_INET6 && !tunnel->v4mapped)
                error = inet6_csk_xmit(skb, NULL);
        else
 #endif
@@ -1151,23 +1150,6 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
        return 0;
 }
 
-/* Automatically called when the skb is freed.
- */
-static void l2tp_sock_wfree(struct sk_buff *skb)
-{
-       sock_put(skb->sk);
-}
-
-/* For data skbs that we transmit, we associate with the tunnel socket
- * but don't do accounting.
- */
-static inline void l2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
-{
-       sock_hold(sk);
-       skb->sk = sk;
-       skb->destructor = l2tp_sock_wfree;
-}
-
 #if IS_ENABLED(CONFIG_IPV6)
 static void l2tp_xmit_ipv6_csum(struct sock *sk, struct sk_buff *skb,
                                int udp_len)
@@ -1221,7 +1203,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
                return NET_XMIT_DROP;
        }
 
-       skb_orphan(skb);
        /* Setup L2TP header */
        session->build_header(session, __skb_push(skb, hdr_len));
 
@@ -1287,8 +1268,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
                break;
        }
 
-       l2tp_skb_set_owner_w(skb, sk);
-
        l2tp_xmit_core(session, skb, fl, data_len);
 out_unlock:
        bh_unlock_sock(sk);
@@ -1861,7 +1840,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_delete);
 /* We come here whenever a session's send_seq, cookie_len or
  * l2specific_len parameters are set.
  */
-static void l2tp_session_set_header_len(struct l2tp_session *session, int version)
+void l2tp_session_set_header_len(struct l2tp_session *session, int version)
 {
        if (version == L2TP_HDR_VER_2) {
                session->hdr_len = 6;
@@ -1874,6 +1853,7 @@ static void l2tp_session_set_header_len(struct l2tp_session *session, int versio
        }
 
 }
+EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
 
 struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
 {
index 1f01ba3435bcf0889a79e510567f19f248b7eef5..3f93ccd6ba9768fe171f4e35e79d613226c1dbc7 100644 (file)
@@ -263,6 +263,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
                      int length, int (*payload_hook)(struct sk_buff *skb));
 int l2tp_session_queue_purge(struct l2tp_session *session);
 int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
+void l2tp_session_set_header_len(struct l2tp_session *session, int version);
 
 int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb,
                  int hdr_len);
index 4cfd722e91536c1de137ec64f1e33bbc7fc5e1ea..bd7387adea9eff25ce7ffd0683589dcdcc020ad0 100644 (file)
@@ -578,8 +578,10 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf
        if (info->attrs[L2TP_ATTR_RECV_SEQ])
                session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]);
 
-       if (info->attrs[L2TP_ATTR_SEND_SEQ])
+       if (info->attrs[L2TP_ATTR_SEND_SEQ]) {
                session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]);
+               l2tp_session_set_header_len(session, session->tunnel->version);
+       }
 
        if (info->attrs[L2TP_ATTR_LNS_MODE])
                session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]);
index ec40bc344be60208ef6eb2e5c0b6c650e383f496..d276e2d4a5894c38c6489eb2f814542a181f6d75 100644 (file)
@@ -254,12 +254,14 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
                po = pppox_sk(sk);
                ppp_input(&po->chan, skb);
        } else {
-               l2tp_info(session, PPPOL2TP_MSG_DATA, "%s: socket not bound\n",
-                         session->name);
+               l2tp_dbg(session, PPPOL2TP_MSG_DATA,
+                        "%s: recv %d byte data frame, passing to L2TP socket\n",
+                        session->name, data_len);
 
-               /* Not bound. Nothing we can do, so discard. */
-               atomic_long_inc(&session->stats.rx_errors);
-               kfree_skb(skb);
+               if (sock_queue_rcv_skb(sk, skb) < 0) {
+                       atomic_long_inc(&session->stats.rx_errors);
+                       kfree_skb(skb);
+               }
        }
 
        return;
@@ -1309,6 +1311,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
                        po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
                                PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
                }
+               l2tp_session_set_header_len(session, session->tunnel->version);
                l2tp_info(session, PPPOL2TP_MSG_CONTROL,
                          "%s: set send_seq=%d\n",
                          session->name, session->send_seq);
index 363d19b5d5c8d4bb88b75d537b69b7bef68f768e..1acb29109b45dfc9d76d83b0506d8ed47932b10d 100644 (file)
@@ -1347,9 +1347,6 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                                    params->vht_capa, sta);
 
        if (params->opmode_notif_used) {
-               enum ieee80211_band band =
-                       ieee80211_get_sdata_band(sdata);
-
                /* returned value is only needed for rc update, but the
                 * rc isn't initialized here yet, so ignore it
                 */
@@ -3647,8 +3644,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
 
 static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
                               u8 *peer, u8 action_code, u8 dialog_token,
-                              u16 status_code, const u8 *extra_ies,
-                              size_t extra_ies_len)
+                              u16 status_code, u32 peer_capability,
+                              const u8 *extra_ies, size_t extra_ies_len)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
index 42c659229a090a7c86f6ad42a33df11afd40b6c8..bd1fd8ea5105fead274e09b7bcd093ba97081a97 100644 (file)
@@ -100,6 +100,12 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
                }
                max_bw = max(max_bw, width);
        }
+
+       /* use the configured bandwidth in case of monitor interface */
+       sdata = rcu_dereference(local->monitor_sdata);
+       if (sdata && rcu_access_pointer(sdata->vif.chanctx_conf) == conf)
+               max_bw = max(max_bw, conf->def.width);
+
        rcu_read_unlock();
 
        return max_bw;
index ebf80f3abd83fe1af18ce94863a0fe1dd090ea19..40a648938985db178b6997f1541bb47a3247b5a8 100644 (file)
@@ -358,6 +358,18 @@ static ssize_t ieee80211_if_parse_tkip_mic_test(
 }
 IEEE80211_IF_FILE_W(tkip_mic_test);
 
+static ssize_t ieee80211_if_parse_beacon_loss(
+       struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
+{
+       if (!ieee80211_sdata_running(sdata) || !sdata->vif.bss_conf.assoc)
+               return -ENOTCONN;
+
+       ieee80211_beacon_loss(&sdata->vif);
+
+       return buflen;
+}
+IEEE80211_IF_FILE_W(beacon_loss);
+
 static ssize_t ieee80211_if_fmt_uapsd_queues(
        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 {
@@ -569,6 +581,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_ADD(beacon_timeout);
        DEBUGFS_ADD_MODE(smps, 0600);
        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
+       DEBUGFS_ADD_MODE(beacon_loss, 0200);
        DEBUGFS_ADD_MODE(uapsd_queues, 0600);
        DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600);
 }
index ef8b385eff04e4c7a279a92722fedc3f84163f6c..fc689f5d971e259381f0a26e13079f1a727fe704 100644 (file)
@@ -354,16 +354,20 @@ drv_sched_scan_start(struct ieee80211_local *local,
        return ret;
 }
 
-static inline void drv_sched_scan_stop(struct ieee80211_local *local,
-                                      struct ieee80211_sub_if_data *sdata)
+static inline int drv_sched_scan_stop(struct ieee80211_local *local,
+                                     struct ieee80211_sub_if_data *sdata)
 {
+       int ret;
+
        might_sleep();
 
        check_sdata_in_driver(sdata);
 
        trace_drv_sched_scan_stop(local, sdata);
-       local->ops->sched_scan_stop(&local->hw, &sdata->vif);
-       trace_drv_return_void(local);
+       ret = local->ops->sched_scan_stop(&local->hw, &sdata->vif);
+       trace_drv_return_int(local, ret);
+
+       return ret;
 }
 
 static inline void drv_sw_scan_start(struct ieee80211_local *local)
index afbe2b203c3ea2bb3bb8694107f34892c7f34adc..c150b68436d78ada5bfbb0825d128d8e89f916e3 100644 (file)
@@ -482,8 +482,6 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
                return;
 
        if (vif->type == NL80211_IFTYPE_STATION) {
-               if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
-                       smps_mode = IEEE80211_SMPS_AUTOMATIC;
                if (sdata->u.mgd.driver_smps_mode == smps_mode)
                        return;
                sdata->u.mgd.driver_smps_mode = smps_mode;
index 4453e2725e407b2650376f1682d183376341e99d..e458ca0dffec12fcaca7e614eb14204760ca9b17 100644 (file)
@@ -283,6 +283,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
        err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
                                            &chandef);
+       if (err < 0) {
+               sdata_info(sdata,
+                          "Failed to join IBSS, invalid chandef\n");
+               return;
+       }
        if (err > 0) {
                if (!ifibss->userspace_handles_dfs) {
                        sdata_info(sdata,
index 0014b5396ce5a4212a978af3f6f9f7594a9de60f..0d1a0f801b9413bdb0ce9a105a2c35811b4a4e30 100644 (file)
@@ -1242,6 +1242,8 @@ struct ieee80211_local {
 
        struct ieee80211_sub_if_data __rcu *p2p_sdata;
 
+       struct napi_struct *napi;
+
        /* virtual monitor interface */
        struct ieee80211_sub_if_data __rcu *monitor_sdata;
        struct cfg80211_chan_def monitor_chandef;
@@ -1698,14 +1700,8 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
 void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
 void ieee80211_add_pending_skb(struct ieee80211_local *local,
                               struct sk_buff *skb);
-void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
-                                  struct sk_buff_head *skbs,
-                                  void (*fn)(void *data), void *data);
-static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
-                                             struct sk_buff_head *skbs)
-{
-       ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
-}
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+                               struct sk_buff_head *skbs);
 void ieee80211_flush_queues(struct ieee80211_local *local,
                            struct ieee80211_sub_if_data *sdata);
 
index 088111af6c7cfee189ff53a6d15768fc2ce79bc4..b8d331e7d883d50fd4fc3adf12c2869ac3beedb7 100644 (file)
@@ -101,9 +101,8 @@ static u32 __ieee80211_idle_on(struct ieee80211_local *local)
 static u32 __ieee80211_recalc_idle(struct ieee80211_local *local,
                                   bool force_active)
 {
-       bool working = false, scanning, active;
+       bool working, scanning, active;
        unsigned int led_trig_start = 0, led_trig_stop = 0;
-       struct ieee80211_roc_work *roc;
 
        lockdep_assert_held(&local->mtx);
 
@@ -111,12 +110,8 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local,
                 !list_empty(&local->chanctx_list) ||
                 local->monitors;
 
-       if (!local->ops->remain_on_channel) {
-               list_for_each_entry(roc, &local->roc_list, list) {
-                       working = true;
-                       break;
-               }
-       }
+       working = !local->ops->remain_on_channel &&
+                 !list_empty(&local->roc_list);
 
        scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
                   test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning);
index 1f7d8422d62d865e1d6b2f84021681e0718c898c..b055f6a55c68e231c5bc73393a7817309a0ed10d 100644 (file)
@@ -1076,6 +1076,18 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_register_hw);
 
+void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi,
+                       struct net_device *napi_dev,
+                       int (*poll)(struct napi_struct *, int),
+                       int weight)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       netif_napi_add(napi_dev, napi, poll, weight);
+       local->napi = napi;
+}
+EXPORT_SYMBOL_GPL(ieee80211_napi_add);
+
 void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
index 2802f9d9279de1527927a88bc731489cc22613c7..ad8b377b4b9f6cfa5d5e222a3c0aff169f4d72d1 100644 (file)
@@ -36,6 +36,7 @@ static struct sk_buff *mps_qos_null_get(struct sta_info *sta)
                                      sdata->vif.addr);
        nullfunc->frame_control = fc;
        nullfunc->duration_id = 0;
+       nullfunc->seq_ctrl = 0;
        /* no address resolution for this frame -> set addr 1 immediately */
        memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
        memset(skb_put(skb, 2), 0, 2); /* append QoS control field */
index 61604834b9146c0b1c6d7360570120d432c1c2c2..94f0af29b7424fd443c1f2c0e0fb7c92ba2b7fbd 100644 (file)
@@ -131,13 +131,13 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata)
        if (unlikely(!sdata->u.mgd.associated))
                return;
 
+       ifmgd->probe_send_count = 0;
+
        if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
                return;
 
        mod_timer(&sdata->u.mgd.conn_mon_timer,
                  round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
-
-       ifmgd->probe_send_count = 0;
 }
 
 static int ecw2cw(int ecw)
@@ -222,6 +222,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        switch (vht_oper->chan_width) {
        case IEEE80211_VHT_CHANWIDTH_USE_HT:
                vht_chandef.width = chandef->width;
+               vht_chandef.center_freq1 = chandef->center_freq1;
                break;
        case IEEE80211_VHT_CHANWIDTH_80MHZ:
                vht_chandef.width = NL80211_CHAN_WIDTH_80;
@@ -271,6 +272,28 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        ret = 0;
 
 out:
+       /*
+        * When tracking the current AP, don't do any further checks if the
+        * new chandef is identical to the one we're currently using for the
+        * connection. This keeps us from playing ping-pong with regulatory,
+        * without it the following can happen (for example):
+        *  - connect to an AP with 80 MHz, world regdom allows 80 MHz
+        *  - AP advertises regdom US
+        *  - CRDA loads regdom US with 80 MHz prohibited (old database)
+        *  - the code below detects an unsupported channel, downgrades, and
+        *    we disconnect from the AP in the caller
+        *  - disconnect causes CRDA to reload world regdomain and the game
+        *    starts anew.
+        * (see https://bugzilla.kernel.org/show_bug.cgi?id=70881)
+        *
+        * It seems possible that there are still scenarios with CSA or real
+        * bandwidth changes where a this could happen, but those cases are
+        * less common and wouldn't completely prevent using the AP.
+        */
+       if (tracking &&
+           cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef))
+               return ret;
+
        /* don't print the message below for VHT mismatch if VHT is disabled */
        if (ret & IEEE80211_STA_DISABLE_VHT)
                vht_chandef = *chandef;
@@ -2249,6 +2272,62 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        /* ignore frame -- wait for timeout */
 }
 
+#define case_WLAN(type) \
+       case WLAN_REASON_##type: return #type
+
+static const char *ieee80211_get_reason_code_string(u16 reason_code)
+{
+       switch (reason_code) {
+       case_WLAN(UNSPECIFIED);
+       case_WLAN(PREV_AUTH_NOT_VALID);
+       case_WLAN(DEAUTH_LEAVING);
+       case_WLAN(DISASSOC_DUE_TO_INACTIVITY);
+       case_WLAN(DISASSOC_AP_BUSY);
+       case_WLAN(CLASS2_FRAME_FROM_NONAUTH_STA);
+       case_WLAN(CLASS3_FRAME_FROM_NONASSOC_STA);
+       case_WLAN(DISASSOC_STA_HAS_LEFT);
+       case_WLAN(STA_REQ_ASSOC_WITHOUT_AUTH);
+       case_WLAN(DISASSOC_BAD_POWER);
+       case_WLAN(DISASSOC_BAD_SUPP_CHAN);
+       case_WLAN(INVALID_IE);
+       case_WLAN(MIC_FAILURE);
+       case_WLAN(4WAY_HANDSHAKE_TIMEOUT);
+       case_WLAN(GROUP_KEY_HANDSHAKE_TIMEOUT);
+       case_WLAN(IE_DIFFERENT);
+       case_WLAN(INVALID_GROUP_CIPHER);
+       case_WLAN(INVALID_PAIRWISE_CIPHER);
+       case_WLAN(INVALID_AKMP);
+       case_WLAN(UNSUPP_RSN_VERSION);
+       case_WLAN(INVALID_RSN_IE_CAP);
+       case_WLAN(IEEE8021X_FAILED);
+       case_WLAN(CIPHER_SUITE_REJECTED);
+       case_WLAN(DISASSOC_UNSPECIFIED_QOS);
+       case_WLAN(DISASSOC_QAP_NO_BANDWIDTH);
+       case_WLAN(DISASSOC_LOW_ACK);
+       case_WLAN(DISASSOC_QAP_EXCEED_TXOP);
+       case_WLAN(QSTA_LEAVE_QBSS);
+       case_WLAN(QSTA_NOT_USE);
+       case_WLAN(QSTA_REQUIRE_SETUP);
+       case_WLAN(QSTA_TIMEOUT);
+       case_WLAN(QSTA_CIPHER_NOT_SUPP);
+       case_WLAN(MESH_PEER_CANCELED);
+       case_WLAN(MESH_MAX_PEERS);
+       case_WLAN(MESH_CONFIG);
+       case_WLAN(MESH_CLOSE);
+       case_WLAN(MESH_MAX_RETRIES);
+       case_WLAN(MESH_CONFIRM_TIMEOUT);
+       case_WLAN(MESH_INVALID_GTK);
+       case_WLAN(MESH_INCONSISTENT_PARAM);
+       case_WLAN(MESH_INVALID_SECURITY);
+       case_WLAN(MESH_PATH_ERROR);
+       case_WLAN(MESH_PATH_NOFORWARD);
+       case_WLAN(MESH_PATH_DEST_UNREACHABLE);
+       case_WLAN(MAC_EXISTS_IN_MBSS);
+       case_WLAN(MESH_CHAN_REGULATORY);
+       case_WLAN(MESH_CHAN);
+       default: return "<unknown>";
+       }
+}
 
 static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgmt *mgmt, size_t len)
@@ -2270,8 +2349,8 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-       sdata_info(sdata, "deauthenticated from %pM (Reason: %u)\n",
-                  bssid, reason_code);
+       sdata_info(sdata, "deauthenticated from %pM (Reason: %u=%s)\n",
+                  bssid, reason_code, ieee80211_get_reason_code_string(reason_code));
 
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
@@ -3792,6 +3871,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
                if (WARN_ON(!chanctx_conf)) {
                        rcu_read_unlock();
+                       sta_info_free(local, new_sta);
                        return -EINVAL;
                }
                rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
@@ -4340,8 +4420,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        bool report_frame = false;
 
        sdata_info(sdata,
-                  "deauthenticating from %pM by local choice (reason=%d)\n",
-                  req->bssid, req->reason_code);
+                  "deauthenticating from %pM by local choice (Reason: %u=%s)\n",
+                  req->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code));
 
        if (ifmgd->auth_data) {
                drv_mgd_prepare_tx(sdata->local, sdata);
@@ -4387,8 +4467,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
                return -ENOLINK;
 
        sdata_info(sdata,
-                  "disassociating from %pM by local choice (reason=%d)\n",
-                  req->bss->bssid, req->reason_code);
+                  "disassociating from %pM by local choice (Reason: %u=%s)\n",
+                  req->bss->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code));
 
        memcpy(bssid, req->bss->bssid, ETH_ALEN);
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
index 593062109c50231d7d131e2165ddb96d7359a35d..5b617660b0ba5c7c12755b6a9b5ffb9a69923c97 100644 (file)
@@ -1092,6 +1092,13 @@ static void sta_ps_end(struct sta_info *sta)
               sta->sta.addr, sta->sta.aid);
 
        if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+               /*
+                * Clear the flag only if the other one is still set
+                * so that the TX path won't start TX'ing new frames
+                * directly ... In the case that the driver flag isn't
+                * set ieee80211_sta_ps_deliver_wakeup() will clear it.
+                */
+               clear_sta_flag(sta, WLAN_STA_PS_STA);
                ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
                       sta->sta.addr, sta->sta.aid);
                return;
@@ -1954,7 +1961,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                /* deliver to local stack */
                skb->protocol = eth_type_trans(skb, dev);
                memset(skb->cb, 0, sizeof(skb->cb));
-               netif_receive_skb(skb);
+               if (rx->local->napi)
+                       napi_gro_receive(rx->local->napi, skb);
+               else
+                       netif_receive_skb(skb);
        }
 
        if (xmit_skb) {
index 88c81616f8f758595e90cced1d503448ce6ba969..836f500dfbf3c989f1f4d21fa281da0d506468fa 100644 (file)
@@ -472,9 +472,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        if (local->ops->hw_scan) {
                u8 *ies;
 
-               local->hw_scan_ies_bufsize = 2 + IEEE80211_MAX_SSID_LEN +
-                                            local->scan_ies_len +
-                                            req->ie_len;
+               local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len;
                local->hw_scan_req = kmalloc(
                                sizeof(*local->hw_scan_req) +
                                req->n_channels * sizeof(req->channels[0]) +
@@ -979,8 +977,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
        struct cfg80211_chan_def chandef;
        int ret, i, iebufsz;
 
-       iebufsz = 2 + IEEE80211_MAX_SSID_LEN +
-                 local->scan_ies_len + req->ie_len;
+       iebufsz = local->scan_ies_len + req->ie_len;
 
        lockdep_assert_held(&local->mtx);
 
@@ -1059,7 +1056,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
        local->sched_scan_req = NULL;
 
        if (rcu_access_pointer(local->sched_scan_sdata))
-               drv_sched_scan_stop(local, sdata);
+               ret = drv_sched_scan_stop(local, sdata);
 
 out:
        mutex_unlock(&local->mtx);
index decd30c1e29053d9a5e3ea56c7ccb66a7407578d..137a192e64bc3c2aa61cc9c5912a89bd3008cbe3 100644 (file)
@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
        return -ENOENT;
 }
 
-static void cleanup_single_sta(struct sta_info *sta)
+static void __cleanup_single_sta(struct sta_info *sta)
 {
        int ac, i;
        struct tid_ampdu_tx *tid_tx;
@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
        struct ps_data *ps;
 
-       if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
+       if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
+           test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
                if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
                    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                        ps = &sdata->bss->ps;
@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct sta_info *sta)
                        return;
 
                clear_sta_flag(sta, WLAN_STA_PS_STA);
+               clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
 
                atomic_dec(&ps->num_sta_ps);
                sta_info_recalc_tim(sta);
@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct sta_info *sta)
                ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
                kfree(tid_tx);
        }
+}
 
+static void cleanup_single_sta(struct sta_info *sta)
+{
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sdata->local;
+
+       __cleanup_single_sta(sta);
        sta_info_free(local, sta);
 }
 
@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        rcu_read_unlock();
 
        spin_lock_init(&sta->lock);
+       spin_lock_init(&sta->ps_lock);
        INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
        INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
        mutex_init(&sta->ampdu_mlme.mtx);
@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
                goto out_err;
        }
 
-       /* notify driver */
-       err = sta_info_insert_drv_state(local, sdata, sta);
-       if (err)
-               goto out_err;
-
        local->num_sta++;
        local->sta_generation++;
        smp_mb();
 
+       /* simplify things and don't accept BA sessions yet */
+       set_sta_flag(sta, WLAN_STA_BLOCK_BA);
+
        /* make the station visible */
        sta_info_hash_add(local, sta);
 
        list_add_rcu(&sta->list, &local->sta_list);
 
+       /* notify driver */
+       err = sta_info_insert_drv_state(local, sdata, sta);
+       if (err)
+               goto out_remove;
+
        set_sta_flag(sta, WLAN_STA_INSERTED);
+       /* accept BA sessions now */
+       clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
 
        ieee80211_recalc_min_chandef(sdata);
        ieee80211_sta_debugfs_add(sta);
@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
                mesh_accept_plinks_update(sdata);
 
        return 0;
+ out_remove:
+       sta_info_hash_del(local, sta);
+       list_del_rcu(&sta->list);
+       local->num_sta--;
+       synchronize_net();
+       __cleanup_single_sta(sta);
  out_err:
        mutex_unlock(&local->sta_mtx);
        rcu_read_lock();
@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
 }
 EXPORT_SYMBOL(ieee80211_find_sta);
 
-static void clear_sta_ps_flags(void *_sta)
+/* powersave support code */
+void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 {
-       struct sta_info *sta = _sta;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sdata->local;
+       struct sk_buff_head pending;
+       int filtered = 0, buffered = 0, ac;
+       unsigned long flags;
        struct ps_data *ps;
 
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_sta)
        else
                return;
 
-       clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-       if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
-               atomic_dec(&ps->num_sta_ps);
-}
-
-/* powersave support code */
-void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
-{
-       struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct ieee80211_local *local = sdata->local;
-       struct sk_buff_head pending;
-       int filtered = 0, buffered = 0, ac;
-       unsigned long flags;
-
        clear_sta_flag(sta, WLAN_STA_SP);
 
        BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 
        skb_queue_head_init(&pending);
 
+       /* sync with ieee80211_tx_h_unicast_ps_buf */
+       spin_lock(&sta->ps_lock);
        /* Send all buffered frames to the station */
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
                int count = skb_queue_len(&pending), tmp;
@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
                buffered += tmp - count;
        }
 
-       ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
+       ieee80211_add_pending_skbs(local, &pending);
+       clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+       clear_sta_flag(sta, WLAN_STA_PS_STA);
+       spin_unlock(&sta->ps_lock);
+
+       atomic_dec(&ps->num_sta_ps);
 
        /* This station just woke up and isn't aware of our SMPS state */
        if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
@@ -1188,6 +1206,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
        memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
        memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
        memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+       nullfunc->seq_ctrl = 0;
 
        skb->priority = tid;
        skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
index d4d85de0d75df91d23b35a6e657b301ff2e589c6..4acc5fc402fa30b11e8f26da93be91eeabcc303a 100644 (file)
@@ -268,6 +268,7 @@ struct ieee80211_tx_latency_stat {
  * @drv_unblock_wk: used for driver PS unblocking
  * @listen_interval: listen interval of this station, when we're acting as AP
  * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
+ * @ps_lock: used for powersave (when mac80211 is the AP) related locking
  * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
  *     when it leaves power saving state or polls
  * @tx_filtered: buffers (per AC) of frames we already tried to
@@ -357,10 +358,8 @@ struct sta_info {
        /* use the accessors defined below */
        unsigned long _flags;
 
-       /*
-        * STA powersave frame queues, no more than the internal
-        * locking required.
-        */
+       /* STA powersave lock and frame queues */
+       spinlock_t ps_lock;
        struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
        struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
        unsigned long driver_buffered_tids;
index 722151fa5dced6aaccee5fe8dab0986d2a78bde2..cd9f80498c48ef2d8811133c4dbc40eada9a39a1 100644 (file)
@@ -477,6 +477,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                       sta->sta.addr, sta->sta.aid, ac);
                if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
                        purge_old_ps_buffers(tx->local);
+
+               /* sync with ieee80211_sta_ps_deliver_wakeup */
+               spin_lock(&sta->ps_lock);
+               /*
+                * STA woke up the meantime and all the frames on ps_tx_buf have
+                * been queued to pending queue. No reordering can happen, go
+                * ahead and Tx the packet.
+                */
+               if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
+                   !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+                       spin_unlock(&sta->ps_lock);
+                       return TX_CONTINUE;
+               }
+
                if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
                        struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
                        ps_dbg(tx->sdata,
@@ -491,6 +505,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
                skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
+               spin_unlock(&sta->ps_lock);
 
                if (!timer_pending(&local->sta_cleanup))
                        mod_timer(&local->sta_cleanup,
index d842af5c8a9520d206f0860ee23d0dba41e44a38..275c94f995f7c8401749cbbafb249bb52a418be7 100644 (file)
@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 }
 
-void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
-                                  struct sk_buff_head *skbs,
-                                  void (*fn)(void *data), void *data)
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+                               struct sk_buff_head *skbs)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct sk_buff *skb;
@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
                __skb_queue_tail(&local->pending[queue], skb);
        }
 
-       if (fn)
-               fn(data);
-
        for (i = 0; i < hw->queues; i++)
                __ieee80211_wake_queue(hw, i,
                        IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
@@ -1766,6 +1762,26 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
+       /*
+        * Reconfigure sched scan if it was interrupted by FW restart or
+        * suspend.
+        */
+       mutex_lock(&local->mtx);
+       sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
+                                               lockdep_is_held(&local->mtx));
+       if (sched_scan_sdata && local->sched_scan_req)
+               /*
+                * Sched scan stopped, but we don't want to report it. Instead,
+                * we're trying to reschedule.
+                */
+               if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
+                                                        local->sched_scan_req))
+                       sched_scan_stopped = true;
+       mutex_unlock(&local->mtx);
+
+       if (sched_scan_stopped)
+               cfg80211_sched_scan_stopped(local->hw.wiphy);
+
        /*
         * If this is for hw restart things are still running.
         * We may want to change that later, however.
@@ -1794,26 +1810,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        WARN_ON(1);
 #endif
 
-       /*
-        * Reconfigure sched scan if it was interrupted by FW restart or
-        * suspend.
-        */
-       mutex_lock(&local->mtx);
-       sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
-                                               lockdep_is_held(&local->mtx));
-       if (sched_scan_sdata && local->sched_scan_req)
-               /*
-                * Sched scan stopped, but we don't want to report it. Instead,
-                * we're trying to reschedule.
-                */
-               if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
-                                                        local->sched_scan_req))
-                       sched_scan_stopped = true;
-       mutex_unlock(&local->mtx);
-
-       if (sched_scan_stopped)
-               cfg80211_sched_scan_stopped(local->hw.wiphy);
-
        return 0;
 }
 
index 21211c60ca988992034bfc330977e846c3fc7010..d51422c778dee359bec450c75b77bfb24ca712f4 100644 (file)
@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
                return IEEE80211_AC_BE;
        }
 
+       if (skb->protocol == sdata->control_port_protocol) {
+               skb->priority = 7;
+               return ieee80211_downgrade_queue(sdata, skb);
+       }
+
        /* use the data classifier to determine what 802.1d tag the
         * data frame has */
        rcu_read_lock();
index 57cf5d1a2e4a4e3de3c6b839cacb5bdf8baf1367..15d62df521825c8581fc25ec25a9caebc8902a72 100644 (file)
@@ -1,2 +1,4 @@
 obj-$(CONFIG_MAC802154)        += mac802154.o
 mac802154-objs         := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o monitor.o wpan.o
+
+ccflags-y += -D__CHECK_ENDIAN__
index b75bb01e5c6b0b859effb0a53d54c7fc75f10b20..10cdb091b775602a1807816256a22f734c0dfb8e 100644 (file)
@@ -27,6 +27,7 @@
 #include <net/netlink.h>
 #include <linux/nl802154.h>
 #include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
 #include <net/route.h>
 #include <net/wpan-phy.h>
 
@@ -46,7 +47,9 @@ int mac802154_slave_open(struct net_device *dev)
        }
 
        if (ipriv->ops->ieee_addr) {
-               res = ipriv->ops->ieee_addr(&ipriv->hw, dev->dev_addr);
+               __le64 addr = ieee802154_devaddr_from_raw(dev->dev_addr);
+
+               res = ipriv->ops->ieee_addr(&ipriv->hw, addr);
                WARN_ON(res);
                if (res)
                        goto err;
index d48422e271109a47d2e7139cf33e2bc727c38f3d..4619486f1da21e728b609f94d785ce683426ccdf 100644 (file)
@@ -76,6 +76,7 @@ struct mac802154_sub_if_data {
 
        __le16 pan_id;
        __le16 short_addr;
+       __le64 extended_addr;
 
        u8 chan;
        u8 page;
@@ -106,11 +107,11 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
                         u8 page, u8 chan);
 
 /* MIB callbacks */
-void mac802154_dev_set_short_addr(struct net_device *dev, u16 val);
-u16 mac802154_dev_get_short_addr(const struct net_device *dev);
+void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val);
+__le16 mac802154_dev_get_short_addr(const struct net_device *dev);
 void mac802154_dev_set_ieee_addr(struct net_device *dev);
-u16 mac802154_dev_get_pan_id(const struct net_device *dev);
-void mac802154_dev_set_pan_id(struct net_device *dev, u16 val);
+__le16 mac802154_dev_get_pan_id(const struct net_device *dev);
+void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val);
 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
 u8 mac802154_dev_get_dsn(const struct net_device *dev);
 
index a99910d4d52f8403a8c2141b473deba885b977ad..15bac3358889198e4b34800896bec9fc12163450 100644 (file)
@@ -40,7 +40,7 @@ static int mac802154_mlme_start_req(struct net_device *dev,
                                    u8 pan_coord, u8 blx,
                                    u8 coord_realign)
 {
-       BUG_ON(addr->addr_type != IEEE802154_ADDR_SHORT);
+       BUG_ON(addr->mode != IEEE802154_ADDR_SHORT);
 
        mac802154_dev_set_pan_id(dev, addr->pan_id);
        mac802154_dev_set_short_addr(dev, addr->short_addr);
index f48f40c1da1ae5870c008b48a64a9bbc4a9434d0..153bd1ddbfbba782b4c2842d7559d8a8917bb474 100644 (file)
@@ -24,7 +24,9 @@
 #include <linux/if_arp.h>
 
 #include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
 #include <net/wpan-phy.h>
+#include <net/ieee802154_netdev.h>
 
 #include "mac802154.h"
 
@@ -79,7 +81,7 @@ static void set_hw_addr_filt(struct net_device *dev, unsigned long changed)
        queue_work(priv->hw->dev_workqueue, &work->work);
 }
 
-void mac802154_dev_set_short_addr(struct net_device *dev, u16 val)
+void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val)
 {
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
 
@@ -96,10 +98,10 @@ void mac802154_dev_set_short_addr(struct net_device *dev, u16 val)
        }
 }
 
-u16 mac802154_dev_get_short_addr(const struct net_device *dev)
+__le16 mac802154_dev_get_short_addr(const struct net_device *dev)
 {
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       u16 ret;
+       __le16 ret;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
@@ -115,19 +117,19 @@ void mac802154_dev_set_ieee_addr(struct net_device *dev)
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
        struct mac802154_priv *mac = priv->hw;
 
+       priv->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
+
        if (mac->ops->set_hw_addr_filt &&
-           memcmp(mac->hw.hw_filt.ieee_addr,
-                  dev->dev_addr, IEEE802154_ADDR_LEN)) {
-               memcpy(mac->hw.hw_filt.ieee_addr,
-                      dev->dev_addr, IEEE802154_ADDR_LEN);
+           mac->hw.hw_filt.ieee_addr != priv->extended_addr) {
+               mac->hw.hw_filt.ieee_addr = priv->extended_addr;
                set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED);
        }
 }
 
-u16 mac802154_dev_get_pan_id(const struct net_device *dev)
+__le16 mac802154_dev_get_pan_id(const struct net_device *dev)
 {
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       u16 ret;
+       __le16 ret;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
@@ -138,7 +140,7 @@ u16 mac802154_dev_get_pan_id(const struct net_device *dev)
        return ret;
 }
 
-void mac802154_dev_set_pan_id(struct net_device *dev, u16 val)
+void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val)
 {
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
 
index 372d8a222b9184e2881d108a087cf9ebaad768e6..80cbee1a2f567aaf3521419bc13e9beab168bb59 100644 (file)
 
 #include "mac802154.h"
 
-static inline int mac802154_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 mac802154_fetch_skb_u16(struct sk_buff *skb, u16 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 2)))
-               return -EINVAL;
-
-       *val = skb->data[0] | (skb->data[1] << 8);
-       skb_pull(skb, 2);
-
-       return 0;
-}
-
-static inline void mac802154_haddr_copy_swap(u8 *dest, const u8 *src)
-{
-       int i;
-       for (i = 0; i < IEEE802154_ADDR_LEN; i++)
-               dest[IEEE802154_ADDR_LEN - i - 1] = src[i];
-}
-
 static int
 mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -76,19 +47,25 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
        switch (cmd) {
        case SIOCGIFADDR:
-               if (priv->pan_id == IEEE802154_PANID_BROADCAST ||
-                   priv->short_addr == IEEE802154_ADDR_BROADCAST) {
+       {
+               u16 pan_id, short_addr;
+
+               pan_id = le16_to_cpu(priv->pan_id);
+               short_addr = le16_to_cpu(priv->short_addr);
+               if (pan_id == IEEE802154_PANID_BROADCAST ||
+                   short_addr == IEEE802154_ADDR_BROADCAST) {
                        err = -EADDRNOTAVAIL;
                        break;
                }
 
                sa->family = AF_IEEE802154;
                sa->addr.addr_type = IEEE802154_ADDR_SHORT;
-               sa->addr.pan_id = priv->pan_id;
-               sa->addr.short_addr = priv->short_addr;
+               sa->addr.pan_id = pan_id;
+               sa->addr.short_addr = short_addr;
 
                err = 0;
                break;
+       }
        case SIOCSIFADDR:
                dev_warn(&dev->dev,
                         "Using DEBUGing ioctl SIOCSIFADDR isn't recommened!\n");
@@ -101,8 +78,8 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        break;
                }
 
-               priv->pan_id = sa->addr.pan_id;
-               priv->short_addr = sa->addr.short_addr;
+               priv->pan_id = cpu_to_le16(sa->addr.pan_id);
+               priv->short_addr = cpu_to_le16(sa->addr.short_addr);
 
                err = 0;
                break;
@@ -128,187 +105,70 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
 static int mac802154_header_create(struct sk_buff *skb,
                                   struct net_device *dev,
                                   unsigned short type,
-                                  const void *_daddr,
-                                  const void *_saddr,
+                                  const void *daddr,
+                                  const void *saddr,
                                   unsigned len)
 {
-       const struct ieee802154_addr *saddr = _saddr;
-       const struct ieee802154_addr *daddr = _daddr;
-       struct ieee802154_addr dev_addr;
+       struct ieee802154_hdr hdr;
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       int pos = 2;
-       u8 head[MAC802154_FRAME_HARD_HEADER_LEN];
-       u16 fc;
+       int hlen;
 
        if (!daddr)
                return -EINVAL;
 
-       head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */
-       fc = mac_cb_type(skb);
-       if (mac_cb_is_ackreq(skb))
-               fc |= IEEE802154_FC_ACK_REQ;
+       memset(&hdr.fc, 0, sizeof(hdr.fc));
+       hdr.fc.type = mac_cb_type(skb);
+       hdr.fc.security_enabled = mac_cb_is_secen(skb);
+       hdr.fc.ack_request = mac_cb_is_ackreq(skb);
 
        if (!saddr) {
                spin_lock_bh(&priv->mib_lock);
 
-               if (priv->short_addr == IEEE802154_ADDR_BROADCAST ||
-                   priv->short_addr == IEEE802154_ADDR_UNDEF ||
-                   priv->pan_id == IEEE802154_PANID_BROADCAST) {
-                       dev_addr.addr_type = IEEE802154_ADDR_LONG;
-                       memcpy(dev_addr.hwaddr, dev->dev_addr,
-                              IEEE802154_ADDR_LEN);
+               if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
+                   priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
+                   priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
+                       hdr.source.mode = IEEE802154_ADDR_LONG;
+                       hdr.source.extended_addr = priv->extended_addr;
                } else {
-                       dev_addr.addr_type = IEEE802154_ADDR_SHORT;
-                       dev_addr.short_addr = priv->short_addr;
+                       hdr.source.mode = IEEE802154_ADDR_SHORT;
+                       hdr.source.short_addr = priv->short_addr;
                }
 
-               dev_addr.pan_id = priv->pan_id;
-               saddr = &dev_addr;
+               hdr.source.pan_id = priv->pan_id;
 
                spin_unlock_bh(&priv->mib_lock);
+       } else {
+               hdr.source = *(const struct ieee802154_addr *)saddr;
        }
 
-       if (daddr->addr_type != IEEE802154_ADDR_NONE) {
-               fc |= (daddr->addr_type << IEEE802154_FC_DAMODE_SHIFT);
-
-               head[pos++] = daddr->pan_id & 0xff;
-               head[pos++] = daddr->pan_id >> 8;
-
-               if (daddr->addr_type == IEEE802154_ADDR_SHORT) {
-                       head[pos++] = daddr->short_addr & 0xff;
-                       head[pos++] = daddr->short_addr >> 8;
-               } else {
-                       mac802154_haddr_copy_swap(head + pos, daddr->hwaddr);
-                       pos += IEEE802154_ADDR_LEN;
-               }
-       }
-
-       if (saddr->addr_type != IEEE802154_ADDR_NONE) {
-               fc |= (saddr->addr_type << IEEE802154_FC_SAMODE_SHIFT);
-
-               if ((saddr->pan_id == daddr->pan_id) &&
-                   (saddr->pan_id != IEEE802154_PANID_BROADCAST)) {
-                       /* PANID compression/intra PAN */
-                       fc |= IEEE802154_FC_INTRA_PAN;
-               } else {
-                       head[pos++] = saddr->pan_id & 0xff;
-                       head[pos++] = saddr->pan_id >> 8;
-               }
-
-               if (saddr->addr_type == IEEE802154_ADDR_SHORT) {
-                       head[pos++] = saddr->short_addr & 0xff;
-                       head[pos++] = saddr->short_addr >> 8;
-               } else {
-                       mac802154_haddr_copy_swap(head + pos, saddr->hwaddr);
-                       pos += IEEE802154_ADDR_LEN;
-               }
-       }
+       hdr.dest = *(const struct ieee802154_addr *)daddr;
 
-       head[0] = fc;
-       head[1] = fc >> 8;
+       hlen = ieee802154_hdr_push(skb, &hdr);
+       if (hlen < 0)
+               return -EINVAL;
 
-       memcpy(skb_push(skb, pos), head, pos);
        skb_reset_mac_header(skb);
-       skb->mac_len = pos;
+       skb->mac_len = hlen;
+
+       if (hlen + len + 2 > dev->mtu)
+               return -EMSGSIZE;
 
-       return pos;
+       return hlen;
 }
 
 static int
 mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
-       const u8 *hdr = skb_mac_header(skb);
-       const u8 *tail = skb_tail_pointer(skb);
+       struct ieee802154_hdr hdr;
        struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
-       u16 fc;
-       int da_type;
-
-       if (hdr + 3 > tail)
-               goto malformed;
-
-       fc = hdr[0] | (hdr[1] << 8);
-
-       hdr += 3;
-
-       da_type = IEEE802154_FC_DAMODE(fc);
-       addr->addr_type = IEEE802154_FC_SAMODE(fc);
-
-       switch (da_type) {
-       case IEEE802154_ADDR_NONE:
-               if (fc & IEEE802154_FC_INTRA_PAN)
-                       goto malformed;
-               break;
-       case IEEE802154_ADDR_LONG:
-               if (fc & IEEE802154_FC_INTRA_PAN) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + IEEE802154_ADDR_LEN > tail)
-                       goto malformed;
-
-               hdr += IEEE802154_ADDR_LEN;
-               break;
-       case IEEE802154_ADDR_SHORT:
-               if (fc & IEEE802154_FC_INTRA_PAN) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + 2 > tail)
-                       goto malformed;
-
-               hdr += 2;
-               break;
-       default:
-               goto malformed;
 
+       if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
+               pr_debug("malformed packet\n");
+               return 0;
        }
 
-       switch (addr->addr_type) {
-       case IEEE802154_ADDR_NONE:
-               break;
-       case IEEE802154_ADDR_LONG:
-               if (!(fc & IEEE802154_FC_INTRA_PAN)) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + IEEE802154_ADDR_LEN > tail)
-                       goto malformed;
-
-               mac802154_haddr_copy_swap(addr->hwaddr, hdr);
-               hdr += IEEE802154_ADDR_LEN;
-               break;
-       case IEEE802154_ADDR_SHORT:
-               if (!(fc & IEEE802154_FC_INTRA_PAN)) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + 2 > tail)
-                       goto malformed;
-
-               addr->short_addr = hdr[0] | (hdr[1] << 8);
-               hdr += 2;
-               break;
-       default:
-               goto malformed;
-       }
-
-       return sizeof(struct ieee802154_addr);
-
-malformed:
-       pr_debug("malformed packet\n");
-       return 0;
+       *addr = hdr.source;
+       return sizeof(*addr);
 }
 
 static netdev_tx_t
@@ -382,8 +242,8 @@ void mac802154_wpan_setup(struct net_device *dev)
        get_random_bytes(&priv->bsn, 1);
        get_random_bytes(&priv->dsn, 1);
 
-       priv->pan_id = IEEE802154_PANID_BROADCAST;
-       priv->short_addr = IEEE802154_ADDR_BROADCAST;
+       priv->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
+       priv->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
 }
 
 static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
@@ -394,13 +254,18 @@ static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
 static int
 mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
 {
+       __le16 span, sshort;
+
        pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
 
        spin_lock_bh(&sdata->mib_lock);
 
-       switch (mac_cb(skb)->da.addr_type) {
+       span = sdata->pan_id;
+       sshort = sdata->short_addr;
+
+       switch (mac_cb(skb)->dest.mode) {
        case IEEE802154_ADDR_NONE:
-               if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE)
+               if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
                        /* FIXME: check if we are PAN coordinator */
                        skb->pkt_type = PACKET_OTHERHOST;
                else
@@ -408,23 +273,22 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
                        skb->pkt_type = PACKET_HOST;
                break;
        case IEEE802154_ADDR_LONG:
-               if (mac_cb(skb)->da.pan_id != sdata->pan_id &&
-                   mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
+               if (mac_cb(skb)->dest.pan_id != span &&
+                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
                        skb->pkt_type = PACKET_OTHERHOST;
-               else if (!memcmp(mac_cb(skb)->da.hwaddr, sdata->dev->dev_addr,
-                                IEEE802154_ADDR_LEN))
+               else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr)
                        skb->pkt_type = PACKET_HOST;
                else
                        skb->pkt_type = PACKET_OTHERHOST;
                break;
        case IEEE802154_ADDR_SHORT:
-               if (mac_cb(skb)->da.pan_id != sdata->pan_id &&
-                   mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
+               if (mac_cb(skb)->dest.pan_id != span &&
+                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
                        skb->pkt_type = PACKET_OTHERHOST;
-               else if (mac_cb(skb)->da.short_addr == sdata->short_addr)
+               else if (mac_cb(skb)->dest.short_addr == sshort)
                        skb->pkt_type = PACKET_HOST;
-               else if (mac_cb(skb)->da.short_addr ==
-                                       IEEE802154_ADDR_BROADCAST)
+               else if (mac_cb(skb)->dest.short_addr ==
+                         cpu_to_le16(IEEE802154_ADDR_BROADCAST))
                        skb->pkt_type = PACKET_BROADCAST;
                else
                        skb->pkt_type = PACKET_OTHERHOST;
@@ -451,88 +315,82 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
        }
 }
 
-static int mac802154_parse_frame_start(struct sk_buff *skb)
+static void mac802154_print_addr(const char *name,
+                                const struct ieee802154_addr *addr)
 {
-       u8 *head = skb->data;
-       u16 fc;
+       if (addr->mode == IEEE802154_ADDR_NONE)
+               pr_debug("%s not present\n", name);
 
-       if (mac802154_fetch_skb_u16(skb, &fc) ||
-           mac802154_fetch_skb_u8(skb, &(mac_cb(skb)->seq)))
-               goto err;
+       pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
+       if (addr->mode == IEEE802154_ADDR_SHORT) {
+               pr_debug("%s is short: %04x\n", name,
+                        le16_to_cpu(addr->short_addr));
+       } else {
+               u64 hw = swab64((__force u64) addr->extended_addr);
 
-       pr_debug("fc: %04x dsn: %02x\n", fc, head[2]);
-
-       mac_cb(skb)->flags = IEEE802154_FC_TYPE(fc);
-       mac_cb(skb)->sa.addr_type = IEEE802154_FC_SAMODE(fc);
-       mac_cb(skb)->da.addr_type = IEEE802154_FC_DAMODE(fc);
+               pr_debug("%s is hardware: %8phC\n", name, &hw);
+       }
+}
 
-       if (fc & IEEE802154_FC_INTRA_PAN)
-               mac_cb(skb)->flags |= MAC_CB_FLAG_INTRAPAN;
+static int mac802154_parse_frame_start(struct sk_buff *skb)
+{
+       int hlen;
+       struct ieee802154_hdr hdr;
 
-       if (mac_cb(skb)->da.addr_type != IEEE802154_ADDR_NONE) {
-               if (mac802154_fetch_skb_u16(skb, &(mac_cb(skb)->da.pan_id)))
-                       goto err;
+       hlen = ieee802154_hdr_pull(skb, &hdr);
+       if (hlen < 0)
+               return -EINVAL;
 
-               /* source PAN id compression */
-               if (mac_cb_is_intrapan(skb))
-                       mac_cb(skb)->sa.pan_id = mac_cb(skb)->da.pan_id;
+       skb->mac_len = hlen;
 
-               pr_debug("dest PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
+       pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc),
+                hdr.seq);
 
-               if (mac_cb(skb)->da.addr_type == IEEE802154_ADDR_SHORT) {
-                       u16 *da = &(mac_cb(skb)->da.short_addr);
+       mac_cb(skb)->flags = hdr.fc.type;
 
-                       if (mac802154_fetch_skb_u16(skb, da))
-                               goto err;
+       if (hdr.fc.ack_request)
+               mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
+       if (hdr.fc.security_enabled)
+               mac_cb(skb)->flags |= MAC_CB_FLAG_SECEN;
 
-                       pr_debug("destination address is short: %04x\n",
-                                mac_cb(skb)->da.short_addr);
-               } else {
-                       if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
-                               goto err;
+       mac802154_print_addr("destination", &hdr.dest);
+       mac802154_print_addr("source", &hdr.source);
 
-                       mac802154_haddr_copy_swap(mac_cb(skb)->da.hwaddr,
-                                                 skb->data);
-                       skb_pull(skb, IEEE802154_ADDR_LEN);
+       mac_cb(skb)->source = hdr.source;
+       mac_cb(skb)->dest = hdr.dest;
 
-                       pr_debug("destination address is hardware\n");
-               }
-       }
+       if (hdr.fc.security_enabled) {
+               u64 key;
 
-       if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) {
-               /* non PAN-compression, fetch source address id */
-               if (!(mac_cb_is_intrapan(skb))) {
-                       u16 *sa_pan = &(mac_cb(skb)->sa.pan_id);
+               pr_debug("seclevel %i\n", hdr.sec.level);
 
-                       if (mac802154_fetch_skb_u16(skb, sa_pan))
-                               goto err;
-               }
-
-               pr_debug("source PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
-
-               if (mac_cb(skb)->sa.addr_type == IEEE802154_ADDR_SHORT) {
-                       u16 *sa = &(mac_cb(skb)->sa.short_addr);
-
-                       if (mac802154_fetch_skb_u16(skb, sa))
-                               goto err;
+               switch (hdr.sec.key_id_mode) {
+               case IEEE802154_SCF_KEY_IMPLICIT:
+                       pr_debug("implicit key\n");
+                       break;
 
-                       pr_debug("source address is short: %04x\n",
-                                mac_cb(skb)->sa.short_addr);
-               } else {
-                       if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
-                               goto err;
+               case IEEE802154_SCF_KEY_INDEX:
+                       pr_debug("key %02x\n", hdr.sec.key_id);
+                       break;
 
-                       mac802154_haddr_copy_swap(mac_cb(skb)->sa.hwaddr,
-                                                 skb->data);
-                       skb_pull(skb, IEEE802154_ADDR_LEN);
+               case IEEE802154_SCF_KEY_SHORT_INDEX:
+                       pr_debug("key %04x:%04x %02x\n",
+                                le32_to_cpu(hdr.sec.short_src) >> 16,
+                                le32_to_cpu(hdr.sec.short_src) & 0xffff,
+                                hdr.sec.key_id);
+                       break;
 
-                       pr_debug("source address is hardware\n");
+               case IEEE802154_SCF_KEY_HW_INDEX:
+                       key = swab64((__force u64) hdr.sec.extended_src);
+                       pr_debug("key source %8phC %02x\n", &key,
+                                hdr.sec.key_id);
+                       break;
                }
+
+               return -EINVAL;
        }
 
        return 0;
-err:
-       return -EINVAL;
 }
 
 void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
index 44cd4f58adf08b914b871d7399942fb58168a623..2f7f5c32c6f90a0eb376d7921aecf167564329ce 100644 (file)
@@ -61,6 +61,15 @@ config IP_SET_HASH_IP
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config IP_SET_HASH_IPMARK
+       tristate "hash:ip,mark set support"
+       depends on IP_SET
+       help
+         This option adds the hash:ip,mark set type support, by which one
+         can store IPv4/IPv6 address and mark pairs.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_SET_HASH_IPPORT
        tristate "hash:ip,port set support"
        depends on IP_SET
index 44b2d38476faeb75a95c5ac8348330a99aa866fd..231f10196cb906fd4cbbe5f58263c5a3ba97886a 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_IP_SET_BITMAP_PORT) += ip_set_bitmap_port.o
 
 # hash types
 obj-$(CONFIG_IP_SET_HASH_IP) += ip_set_hash_ip.o
+obj-$(CONFIG_IP_SET_HASH_IPMARK) += ip_set_hash_ipmark.o
 obj-$(CONFIG_IP_SET_HASH_IPPORT) += ip_set_hash_ipport.o
 obj-$(CONFIG_IP_SET_HASH_IPPORTIP) += ip_set_hash_ipportip.o
 obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o
index de770ec39e5112e4cbf5b4b90629144bad1d957b..117208321f16997af9f24bee1f86519f8f8fa26e 100644 (file)
@@ -54,10 +54,10 @@ MODULE_DESCRIPTION("core IP set support");
 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
 
 /* When the nfnl mutex is held: */
-#define nfnl_dereference(p)            \
+#define ip_set_dereference(p)          \
        rcu_dereference_protected(p, 1)
-#define nfnl_set(inst, id)                     \
-       nfnl_dereference((inst)->ip_set_list)[id]
+#define ip_set(inst, id)               \
+       ip_set_dereference((inst)->ip_set_list)[id]
 
 /*
  * The set types are implemented in modules and registered set types
@@ -368,6 +368,8 @@ ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len)
 
        if (tb[IPSET_ATTR_CADT_FLAGS])
                cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+       if (cadt_flags & IPSET_FLAG_WITH_FORCEADD)
+               set->flags |= IPSET_CREATE_FLAG_FORCEADD;
        for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
                if (!add_extension(id, cadt_flags, tb))
                        continue;
@@ -510,7 +512,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
 
        if (opt->dim < set->type->dimension ||
            !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
-               return 0;
+               return -IPSET_ERR_TYPE_MISMATCH;
 
        write_lock_bh(&set->lock);
        ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
@@ -533,7 +535,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
 
        if (opt->dim < set->type->dimension ||
            !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
-               return 0;
+               return -IPSET_ERR_TYPE_MISMATCH;
 
        write_lock_bh(&set->lock);
        ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
@@ -640,7 +642,7 @@ ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index)
                return IPSET_INVALID_ID;
 
        nfnl_lock(NFNL_SUBSYS_IPSET);
-       set = nfnl_set(inst, index);
+       set = ip_set(inst, index);
        if (set)
                __ip_set_get(set);
        else
@@ -666,7 +668,7 @@ ip_set_nfnl_put(struct net *net, ip_set_id_t index)
 
        nfnl_lock(NFNL_SUBSYS_IPSET);
        if (!inst->is_deleted) { /* already deleted from ip_set_net_exit() */
-               set = nfnl_set(inst, index);
+               set = ip_set(inst, index);
                if (set != NULL)
                        __ip_set_put(set);
        }
@@ -734,7 +736,7 @@ find_set_and_id(struct ip_set_net *inst, const char *name, ip_set_id_t *id)
 
        *id = IPSET_INVALID_ID;
        for (i = 0; i < inst->ip_set_max; i++) {
-               set = nfnl_set(inst, i);
+               set = ip_set(inst, i);
                if (set != NULL && STREQ(set->name, name)) {
                        *id = i;
                        break;
@@ -760,7 +762,7 @@ find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index,
 
        *index = IPSET_INVALID_ID;
        for (i = 0;  i < inst->ip_set_max; i++) {
-               s = nfnl_set(inst, i);
+               s = ip_set(inst, i);
                if (s == NULL) {
                        if (*index == IPSET_INVALID_ID)
                                *index = i;
@@ -883,7 +885,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
                if (!list)
                        goto cleanup;
                /* nfnl mutex is held, both lists are valid */
-               tmp = nfnl_dereference(inst->ip_set_list);
+               tmp = ip_set_dereference(inst->ip_set_list);
                memcpy(list, tmp, sizeof(struct ip_set *) * inst->ip_set_max);
                rcu_assign_pointer(inst->ip_set_list, list);
                /* Make sure all current packets have passed through */
@@ -900,7 +902,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
         * Finally! Add our shiny new set to the list, and be done.
         */
        pr_debug("create: '%s' created with index %u!\n", set->name, index);
-       nfnl_set(inst, index) = set;
+       ip_set(inst, index) = set;
 
        return ret;
 
@@ -925,10 +927,10 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {
 static void
 ip_set_destroy_set(struct ip_set_net *inst, ip_set_id_t index)
 {
-       struct ip_set *set = nfnl_set(inst, index);
+       struct ip_set *set = ip_set(inst, index);
 
        pr_debug("set: %s\n",  set->name);
-       nfnl_set(inst, index) = NULL;
+       ip_set(inst, index) = NULL;
 
        /* Must call it without holding any lock */
        set->variant->destroy(set);
@@ -962,7 +964,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
        read_lock_bh(&ip_set_ref_lock);
        if (!attr[IPSET_ATTR_SETNAME]) {
                for (i = 0; i < inst->ip_set_max; i++) {
-                       s = nfnl_set(inst, i);
+                       s = ip_set(inst, i);
                        if (s != NULL && s->ref) {
                                ret = -IPSET_ERR_BUSY;
                                goto out;
@@ -970,7 +972,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
                }
                read_unlock_bh(&ip_set_ref_lock);
                for (i = 0; i < inst->ip_set_max; i++) {
-                       s = nfnl_set(inst, i);
+                       s = ip_set(inst, i);
                        if (s != NULL)
                                ip_set_destroy_set(inst, i);
                }
@@ -1020,7 +1022,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
 
        if (!attr[IPSET_ATTR_SETNAME]) {
                for (i = 0; i < inst->ip_set_max; i++) {
-                       s = nfnl_set(inst, i);
+                       s = ip_set(inst, i);
                        if (s != NULL)
                                ip_set_flush_set(s);
                }
@@ -1074,7 +1076,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
 
        name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
        for (i = 0; i < inst->ip_set_max; i++) {
-               s = nfnl_set(inst, i);
+               s = ip_set(inst, i);
                if (s != NULL && STREQ(s->name, name2)) {
                        ret = -IPSET_ERR_EXIST_SETNAME2;
                        goto out;
@@ -1134,8 +1136,8 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
 
        write_lock_bh(&ip_set_ref_lock);
        swap(from->ref, to->ref);
-       nfnl_set(inst, from_id) = to;
-       nfnl_set(inst, to_id) = from;
+       ip_set(inst, from_id) = to;
+       ip_set(inst, to_id) = from;
        write_unlock_bh(&ip_set_ref_lock);
 
        return 0;
@@ -1157,7 +1159,7 @@ ip_set_dump_done(struct netlink_callback *cb)
        struct ip_set_net *inst = (struct ip_set_net *)cb->args[IPSET_CB_NET];
        if (cb->args[IPSET_CB_ARG0]) {
                pr_debug("release set %s\n",
-                        nfnl_set(inst, cb->args[IPSET_CB_INDEX])->name);
+                        ip_set(inst, cb->args[IPSET_CB_INDEX])->name);
                __ip_set_put_byindex(inst,
                        (ip_set_id_t) cb->args[IPSET_CB_INDEX]);
        }
@@ -1254,7 +1256,7 @@ dump_last:
                 dump_type, dump_flags, cb->args[IPSET_CB_INDEX]);
        for (; cb->args[IPSET_CB_INDEX] < max; cb->args[IPSET_CB_INDEX]++) {
                index = (ip_set_id_t) cb->args[IPSET_CB_INDEX];
-               set = nfnl_set(inst, index);
+               set = ip_set(inst, index);
                if (set == NULL) {
                        if (dump_type == DUMP_ONE) {
                                ret = -ENOENT;
@@ -1332,7 +1334,7 @@ next_set:
 release_refcount:
        /* If there was an error or set is done, release set */
        if (ret || !cb->args[IPSET_CB_ARG0]) {
-               pr_debug("release set %s\n", nfnl_set(inst, index)->name);
+               pr_debug("release set %s\n", ip_set(inst, index)->name);
                __ip_set_put_byindex(inst, index);
                cb->args[IPSET_CB_ARG0] = 0;
        }
@@ -1887,7 +1889,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
                find_set_and_id(inst, req_get->set.name, &id);
                req_get->set.index = id;
                if (id != IPSET_INVALID_ID)
-                       req_get->family = nfnl_set(inst, id)->family;
+                       req_get->family = ip_set(inst, id)->family;
                nfnl_unlock(NFNL_SUBSYS_IPSET);
                goto copy;
        }
@@ -1901,7 +1903,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
                        goto done;
                }
                nfnl_lock(NFNL_SUBSYS_IPSET);
-               set = nfnl_set(inst, req_get->set.index);
+               set = ip_set(inst, req_get->set.index);
                strncpy(req_get->set.name, set ? set->name : "",
                        IPSET_MAXNAMELEN);
                nfnl_unlock(NFNL_SUBSYS_IPSET);
@@ -1945,7 +1947,6 @@ ip_set_net_init(struct net *net)
                return -ENOMEM;
        inst->is_deleted = 0;
        rcu_assign_pointer(inst->ip_set_list, list);
-       pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL);
        return 0;
 }
 
@@ -1960,7 +1961,7 @@ ip_set_net_exit(struct net *net)
        inst->is_deleted = 1; /* flag for ip_set_nfnl_put */
 
        for (i = 0; i < inst->ip_set_max; i++) {
-               set = nfnl_set(inst, i);
+               set = ip_set(inst, i);
                if (set != NULL)
                        ip_set_destroy_set(inst, i);
        }
@@ -1996,6 +1997,7 @@ ip_set_init(void)
                nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
                return ret;
        }
+       pr_info("ip_set: protocol %u\n", IPSET_PROTOCOL);
        return 0;
 }
 
index be6932ad3a8626d6c06e99091b32f540b7afd338..61c7fb052802e7c0cb291289ee29c484b4f84179 100644 (file)
@@ -263,6 +263,9 @@ struct htype {
        u32 maxelem;            /* max elements in the hash */
        u32 elements;           /* current element (vs timeout) */
        u32 initval;            /* random jhash init value */
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       u32 markmask;           /* markmask value for mark mask to store */
+#endif
        struct timer_list gc;   /* garbage collection when timeout enabled */
        struct mtype_elem next; /* temporary storage for uadd */
 #ifdef IP_SET_HASH_WITH_MULTI
@@ -453,6 +456,9 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b)
               a->timeout == b->timeout &&
 #ifdef IP_SET_HASH_WITH_NETMASK
               x->netmask == y->netmask &&
+#endif
+#ifdef IP_SET_HASH_WITH_MARKMASK
+              x->markmask == y->markmask &&
 #endif
               a->extensions == b->extensions;
 }
@@ -627,6 +633,18 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        bool flag_exist = flags & IPSET_FLAG_EXIST;
        u32 key, multi = 0;
 
+       if (h->elements >= h->maxelem && SET_WITH_FORCEADD(set)) {
+               rcu_read_lock_bh();
+               t = rcu_dereference_bh(h->table);
+               key = HKEY(value, h->initval, t->htable_bits);
+               n = hbucket(t,key);
+               if (n->pos) {
+                       /* Choosing the first entry in the array to replace */
+                       j = 0;
+                       goto reuse_slot;
+               }
+               rcu_read_unlock_bh();
+       }
        if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
                /* FIXME: when set is full, we slow down here */
                mtype_expire(set, h, NLEN(set->family), set->dsize);
@@ -907,6 +925,10 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
        if (h->netmask != HOST_MASK &&
            nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask))
                goto nla_put_failure;
+#endif
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       if (nla_put_u32(skb, IPSET_ATTR_MARKMASK, h->markmask))
+               goto nla_put_failure;
 #endif
        if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
            nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
@@ -1016,6 +1038,9 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
                            struct nlattr *tb[], u32 flags)
 {
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       u32 markmask;
+#endif
        u8 hbits;
 #ifdef IP_SET_HASH_WITH_NETMASK
        u8 netmask;
@@ -1026,6 +1051,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
 
        if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
+
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       markmask = 0xffffffff;
+#endif
 #ifdef IP_SET_HASH_WITH_NETMASK
        netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
        pr_debug("Create set %s with family %s\n",
@@ -1034,6 +1063,9 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
 
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
+#ifdef IP_SET_HASH_WITH_MARKMASK
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_MARKMASK) ||
+#endif
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
                return -IPSET_ERR_PROTOCOL;
@@ -1057,6 +1089,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
                        return -IPSET_ERR_INVALID_NETMASK;
        }
 #endif
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       if (tb[IPSET_ATTR_MARKMASK]) {
+               markmask = ntohl(nla_get_u32(tb[IPSET_ATTR_MARKMASK]));
+
+               if ((markmask > 4294967295u) || markmask == 0)
+                       return -IPSET_ERR_INVALID_MARKMASK;
+       }
+#endif
 
        hsize = sizeof(*h);
 #ifdef IP_SET_HASH_WITH_NETS
@@ -1070,6 +1110,9 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
        h->maxelem = maxelem;
 #ifdef IP_SET_HASH_WITH_NETMASK
        h->netmask = netmask;
+#endif
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       h->markmask = markmask;
 #endif
        get_random_bytes(&h->initval, sizeof(h->initval));
        set->timeout = IPSET_NO_TIMEOUT;
index e65fc2423d56dd2b21cee513786eec41ceabefc9..dd40607f878e28e8c5c411a24fb8e36ef7db5d46 100644 (file)
@@ -25,7 +25,8 @@
 
 #define IPSET_TYPE_REV_MIN     0
 /*                             1          Counters support */
-#define IPSET_TYPE_REV_MAX     2       /* Comments support */
+/*                             2          Comments support */
+#define IPSET_TYPE_REV_MAX     3       /* Forceadd support */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
diff --git a/net/netfilter/ipset/ip_set_hash_ipmark.c b/net/netfilter/ipset/ip_set_hash_ipmark.c
new file mode 100644 (file)
index 0000000..4eff0a2
--- /dev/null
@@ -0,0 +1,321 @@
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2013 Smoothwall Ltd. <vytas.dauksa@smoothwall.net>
+ *
+ * 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.
+ */
+
+/* Kernel module implementing an IP set type: the hash:ip,mark type */
+
+#include <linux/jhash.h>
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/netlink.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter/ipset/pfxlen.h>
+#include <linux/netfilter/ipset/ip_set.h>
+#include <linux/netfilter/ipset/ip_set_hash.h>
+
+#define IPSET_TYPE_REV_MIN     0
+#define IPSET_TYPE_REV_MAX     1       /* Forceadd support */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@smoothwall.net>");
+IP_SET_MODULE_DESC("hash:ip,mark", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+MODULE_ALIAS("ip_set_hash:ip,mark");
+
+/* Type specific function prefix */
+#define HTYPE          hash_ipmark
+#define IP_SET_HASH_WITH_MARKMASK
+
+/* IPv4 variant */
+
+/* Member elements */
+struct hash_ipmark4_elem {
+       __be32 ip;
+       __u32 mark;
+};
+
+/* Common functions */
+
+static inline bool
+hash_ipmark4_data_equal(const struct hash_ipmark4_elem *ip1,
+                       const struct hash_ipmark4_elem *ip2,
+                       u32 *multi)
+{
+       return ip1->ip == ip2->ip &&
+              ip1->mark == ip2->mark;
+}
+
+static bool
+hash_ipmark4_data_list(struct sk_buff *skb,
+                      const struct hash_ipmark4_elem *data)
+{
+       if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+           nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark)))
+               goto nla_put_failure;
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
+
+static inline void
+hash_ipmark4_data_next(struct hash_ipmark4_elem *next,
+                      const struct hash_ipmark4_elem *d)
+{
+       next->ip = d->ip;
+}
+
+#define MTYPE           hash_ipmark4
+#define PF              4
+#define HOST_MASK       32
+#define HKEY_DATALEN   sizeof(struct hash_ipmark4_elem)
+#include "ip_set_hash_gen.h"
+
+static int
+hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb,
+                 const struct xt_action_param *par,
+                 enum ipset_adt adt, struct ip_set_adt_opt *opt)
+{
+       const struct hash_ipmark *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipmark4_elem e = { };
+       struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+
+       e.mark = skb->mark;
+       e.mark &= h->markmask;
+
+       ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
+       return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
+}
+
+static int
+hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
+                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
+{
+       const struct hash_ipmark *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipmark4_elem e = { };
+       struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+       u32 ip, ip_to = 0;
+       int ret;
+
+       if (unlikely(!tb[IPSET_ATTR_IP] ||
+                    !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_LINENO])
+               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
+       ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) ||
+             ip_set_get_extensions(set, tb, &ext);
+       if (ret)
+               return ret;
+
+       e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK]));
+       e.mark &= h->markmask;
+
+       if (adt == IPSET_TEST ||
+           !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) {
+               ret = adtfn(set, &e, &ext, &ext, flags);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
+
+       ip_to = ip = ntohl(e.ip);
+       if (tb[IPSET_ATTR_IP_TO]) {
+               ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
+               if (ret)
+                       return ret;
+               if (ip > ip_to)
+                       swap(ip, ip_to);
+       } else if (tb[IPSET_ATTR_CIDR]) {
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+
+               if (!cidr || cidr > 32)
+                       return -IPSET_ERR_INVALID_CIDR;
+               ip_set_mask_from_to(ip, ip_to, cidr);
+       }
+
+       if (retried)
+               ip = ntohl(h->next.ip);
+       for (; !before(ip_to, ip); ip++) {
+               e.ip = htonl(ip);
+               ret = adtfn(set, &e, &ext, &ext, flags);
+
+               if (ret && !ip_set_eexist(ret, flags))
+                       return ret;
+               else
+                       ret = 0;
+       }
+       return ret;
+}
+
+/* IPv6 variant */
+
+struct hash_ipmark6_elem {
+       union nf_inet_addr ip;
+       __u32 mark;
+};
+
+/* Common functions */
+
+static inline bool
+hash_ipmark6_data_equal(const struct hash_ipmark6_elem *ip1,
+                       const struct hash_ipmark6_elem *ip2,
+                       u32 *multi)
+{
+       return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
+              ip1->mark == ip2->mark;
+}
+
+static bool
+hash_ipmark6_data_list(struct sk_buff *skb,
+                      const struct hash_ipmark6_elem *data)
+{
+       if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
+           nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark)))
+               goto nla_put_failure;
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
+
+static inline void
+hash_ipmark6_data_next(struct hash_ipmark4_elem *next,
+                      const struct hash_ipmark6_elem *d)
+{
+}
+
+#undef MTYPE
+#undef PF
+#undef HOST_MASK
+#undef HKEY_DATALEN
+
+#define MTYPE          hash_ipmark6
+#define PF             6
+#define HOST_MASK      128
+#define HKEY_DATALEN   sizeof(struct hash_ipmark6_elem)
+#define        IP_SET_EMIT_CREATE
+#include "ip_set_hash_gen.h"
+
+
+static int
+hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb,
+                 const struct xt_action_param *par,
+                 enum ipset_adt adt, struct ip_set_adt_opt *opt)
+{
+       const struct hash_ipmark *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipmark6_elem e = { };
+       struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+
+       e.mark = skb->mark;
+       e.mark &= h->markmask;
+
+       ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+       return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
+}
+
+static int
+hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[],
+                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
+{
+       const struct hash_ipmark *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipmark6_elem e = { };
+       struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+       int ret;
+
+       if (unlikely(!tb[IPSET_ATTR_IP] ||
+                    !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
+                    tb[IPSET_ATTR_IP_TO] ||
+                    tb[IPSET_ATTR_CIDR]))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_LINENO])
+               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
+       ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+             ip_set_get_extensions(set, tb, &ext);
+       if (ret)
+               return ret;
+
+       e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK]));
+       e.mark &= h->markmask;
+
+       if (adt == IPSET_TEST) {
+               ret = adtfn(set, &e, &ext, &ext, flags);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
+
+       ret = adtfn(set, &e, &ext, &ext, flags);
+       if (ret && !ip_set_eexist(ret, flags))
+               return ret;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+static struct ip_set_type hash_ipmark_type __read_mostly = {
+       .name           = "hash:ip,mark",
+       .protocol       = IPSET_PROTOCOL,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_MARK,
+       .dimension      = IPSET_DIM_TWO,
+       .family         = NFPROTO_UNSPEC,
+       .revision_min   = IPSET_TYPE_REV_MIN,
+       .revision_max   = IPSET_TYPE_REV_MAX,
+       .create         = hash_ipmark_create,
+       .create_policy  = {
+               [IPSET_ATTR_MARKMASK]   = { .type = NLA_U32 },
+               [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+               [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+               [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+               [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
+               [IPSET_ATTR_MARK]       = { .type = NLA_U32 },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+               [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
+               [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
+               [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING },
+       },
+       .me             = THIS_MODULE,
+};
+
+static int __init
+hash_ipmark_init(void)
+{
+       return ip_set_type_register(&hash_ipmark_type);
+}
+
+static void __exit
+hash_ipmark_fini(void)
+{
+       ip_set_type_unregister(&hash_ipmark_type);
+}
+
+module_init(hash_ipmark_init);
+module_exit(hash_ipmark_fini);
index 525a595dd1fe4bf0efe6db7ca9cc06d995c66430..7597b82a8b033bd37c8a5f64dae02e8aa9137a19 100644 (file)
@@ -27,7 +27,8 @@
 #define IPSET_TYPE_REV_MIN     0
 /*                             1    SCTP and UDPLITE support added */
 /*                             2    Counters support added */
-#define IPSET_TYPE_REV_MAX     3 /* Comments support added */
+/*                             3    Comments support added */
+#define IPSET_TYPE_REV_MAX     4 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index f5636631466eb3ee98509e8b832e46da4ad9a417..672655ffd573404b2f2f5bf097b7a8d01f0c4c14 100644 (file)
@@ -27,7 +27,8 @@
 #define IPSET_TYPE_REV_MIN     0
 /*                             1    SCTP and UDPLITE support added */
 /*                             2    Counters support added */
-#define IPSET_TYPE_REV_MAX     3 /* Comments support added */
+/*                             3    Comments support added */
+#define IPSET_TYPE_REV_MAX     4 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index 5d87fe8a41ffa4888a70b6d91897360e30c253bc..7308d84f9277813f16351b692f75218ff1a451b3 100644 (file)
@@ -29,7 +29,8 @@
 /*                             2    Range as input support for IPv4 added */
 /*                             3    nomatch flag support added */
 /*                             4    Counters support added */
-#define IPSET_TYPE_REV_MAX     5 /* Comments support added */
+/*                             5    Comments support added */
+#define IPSET_TYPE_REV_MAX     6 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index 8295cf4f9fdcfdb3d3da4b72792add9fc83156ad..4c7d495783a3aefa9447d4b37114bd3715928b0a 100644 (file)
@@ -26,7 +26,8 @@
 /*                             1    Range as input support for IPv4 added */
 /*                             2    nomatch flag support added */
 /*                             3    Counters support added */
-#define IPSET_TYPE_REV_MAX     4 /* Comments support added */
+/*                             4    Comments support added */
+#define IPSET_TYPE_REV_MAX     5 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index b827a0f1f3510bc0fa4e6b0a498738806ac62e81..db2606805b3575b91a87cded299222c571fbf6ba 100644 (file)
@@ -27,7 +27,8 @@
 /*                             1    nomatch flag support added */
 /*                             2    /0 support added */
 /*                             3    Counters support added */
-#define IPSET_TYPE_REV_MAX     4 /* Comments support added */
+/*                             4    Comments support added */
+#define IPSET_TYPE_REV_MAX     5 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index 6226803fc490ce33c53994c344a1c034b9b0cce9..3e99987e4bf248f6d6085118dba52a4c24ee108a 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/netfilter/ipset/ip_set_hash.h>
 
 #define IPSET_TYPE_REV_MIN     0
-#define IPSET_TYPE_REV_MAX     0
+#define IPSET_TYPE_REV_MAX     1       /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
@@ -112,10 +112,10 @@ hash_netnet4_data_list(struct sk_buff *skb,
            (flags &&
             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
                goto nla_put_failure;
-       return 0;
+       return false;
 
 nla_put_failure:
-       return 1;
+       return true;
 }
 
 static inline void
@@ -334,10 +334,10 @@ hash_netnet6_data_list(struct sk_buff *skb,
            (flags &&
             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
                goto nla_put_failure;
-       return 0;
+       return false;
 
 nla_put_failure:
-       return 1;
+       return true;
 }
 
 static inline void
index 7097fb0141bf6e1363ca0b0342451e66c34773b4..1c645fbd09c7d6bcb337b90977ae2536b2ec9ebd 100644 (file)
@@ -28,7 +28,8 @@
 /*                             2    Range as input support for IPv4 added */
 /*                             3    nomatch flag support added */
 /*                             4    Counters support added */
-#define IPSET_TYPE_REV_MAX     5 /* Comments support added */
+/*                             5    Comments support added */
+#define IPSET_TYPE_REV_MAX     6 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index 703d1192a6a225214f1ffd28c6ab926110942c32..c0d2ba73f8b2394995bba3737a833cc47138d581 100644 (file)
@@ -25,7 +25,8 @@
 #include <linux/netfilter/ipset/ip_set_hash.h>
 
 #define IPSET_TYPE_REV_MIN     0
-#define IPSET_TYPE_REV_MAX     0 /* Comments support added */
+/*                             0    Comments support added */
+#define IPSET_TYPE_REV_MAX     1 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
index 4f29fa97044b18523967cdc8b8c6ab272376a2fb..04d15fdc99eec407545c2c598c7a158de0daade9 100644 (file)
@@ -7,8 +7,8 @@
 
 #define E(a, b, c, d) \
        {.ip6 = { \
-               __constant_htonl(a), __constant_htonl(b), \
-               __constant_htonl(c), __constant_htonl(d), \
+               htonl(a), htonl(b), \
+               htonl(c), htonl(d), \
        } }
 
 /*
index 35be035ee0cec79b5b797efb46c287661b8dbc93..c42e83d2751cdc2dd1324a3b9db3e36b615d2fb5 100644 (file)
@@ -2177,10 +2177,10 @@ static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v)
                __u64 inbytes, outbytes;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&u->syncp);
+                       start = u64_stats_fetch_begin_irq(&u->syncp);
                        inbytes = u->ustats.inbytes;
                        outbytes = u->ustats.outbytes;
-               } while (u64_stats_fetch_retry_bh(&u->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&u->syncp, start));
 
                seq_printf(seq, "%3X %8X %8X %8X %16LX %16LX\n",
                           i, u->ustats.conns, u->ustats.inpkts,
@@ -3580,7 +3580,7 @@ out:
 }
 
 
-static const struct genl_ops ip_vs_genl_ops[] __read_mostly = {
+static const struct genl_ops ip_vs_genl_ops[] = {
        {
                .cmd    = IPVS_CMD_NEW_SERVICE,
                .flags  = GENL_ADMIN_PERM,
index ca056a331e60b23f1b6e542fd640b2b996878335..547ff33c1efdb0cb92f3f8890640a77bba3a73b5 100644 (file)
@@ -238,7 +238,7 @@ static void ip_vs_lblc_flush(struct ip_vs_service *svc)
 
        spin_lock_bh(&svc->sched_lock);
        tbl->dead = 1;
-       for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
+       for (i = 0; i < IP_VS_LBLC_TAB_SIZE; i++) {
                hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) {
                        ip_vs_lblc_del(en);
                        atomic_dec(&tbl->entries);
@@ -265,7 +265,7 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
        unsigned long now = jiffies;
        int i, j;
 
-       for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
+       for (i = 0, j = tbl->rover; i < IP_VS_LBLC_TAB_SIZE; i++) {
                j = (j + 1) & IP_VS_LBLC_TAB_MASK;
 
                spin_lock(&svc->sched_lock);
@@ -321,7 +321,7 @@ static void ip_vs_lblc_check_expire(unsigned long data)
        if (goal > tbl->max_size/2)
                goal = tbl->max_size/2;
 
-       for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
+       for (i = 0, j = tbl->rover; i < IP_VS_LBLC_TAB_SIZE; i++) {
                j = (j + 1) & IP_VS_LBLC_TAB_MASK;
 
                spin_lock(&svc->sched_lock);
@@ -340,7 +340,7 @@ static void ip_vs_lblc_check_expire(unsigned long data)
        tbl->rover = j;
 
   out:
-       mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL);
+       mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL);
 }
 
 
@@ -363,7 +363,7 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
        /*
         *    Initialize the hash buckets
         */
-       for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
+       for (i = 0; i < IP_VS_LBLC_TAB_SIZE; i++) {
                INIT_HLIST_HEAD(&tbl->bucket[i]);
        }
        tbl->max_size = IP_VS_LBLC_TAB_SIZE*16;
@@ -536,8 +536,7 @@ out:
 /*
  *      IPVS LBLC Scheduler structure
  */
-static struct ip_vs_scheduler ip_vs_lblc_scheduler =
-{
+static struct ip_vs_scheduler ip_vs_lblc_scheduler = {
        .name =                 "lblc",
        .refcnt =               ATOMIC_INIT(0),
        .module =               THIS_MODULE,
index 356bef519fe5b781f6225557f64186c0075852a1..6dba48efe01e83bebda511e56410b403a8d4b968 100644 (file)
@@ -60,8 +60,59 @@ int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
                                      const struct nlattr *attr) __read_mostly;
 EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
 
-DEFINE_SPINLOCK(nf_conntrack_lock);
-EXPORT_SYMBOL_GPL(nf_conntrack_lock);
+__cacheline_aligned_in_smp spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS];
+EXPORT_SYMBOL_GPL(nf_conntrack_locks);
+
+__cacheline_aligned_in_smp DEFINE_SPINLOCK(nf_conntrack_expect_lock);
+EXPORT_SYMBOL_GPL(nf_conntrack_expect_lock);
+
+static void nf_conntrack_double_unlock(unsigned int h1, unsigned int h2)
+{
+       h1 %= CONNTRACK_LOCKS;
+       h2 %= CONNTRACK_LOCKS;
+       spin_unlock(&nf_conntrack_locks[h1]);
+       if (h1 != h2)
+               spin_unlock(&nf_conntrack_locks[h2]);
+}
+
+/* return true if we need to recompute hashes (in case hash table was resized) */
+static bool nf_conntrack_double_lock(struct net *net, unsigned int h1,
+                                    unsigned int h2, unsigned int sequence)
+{
+       h1 %= CONNTRACK_LOCKS;
+       h2 %= CONNTRACK_LOCKS;
+       if (h1 <= h2) {
+               spin_lock(&nf_conntrack_locks[h1]);
+               if (h1 != h2)
+                       spin_lock_nested(&nf_conntrack_locks[h2],
+                                        SINGLE_DEPTH_NESTING);
+       } else {
+               spin_lock(&nf_conntrack_locks[h2]);
+               spin_lock_nested(&nf_conntrack_locks[h1],
+                                SINGLE_DEPTH_NESTING);
+       }
+       if (read_seqcount_retry(&net->ct.generation, sequence)) {
+               nf_conntrack_double_unlock(h1, h2);
+               return true;
+       }
+       return false;
+}
+
+static void nf_conntrack_all_lock(void)
+{
+       int i;
+
+       for (i = 0; i < CONNTRACK_LOCKS; i++)
+               spin_lock_nested(&nf_conntrack_locks[i], i);
+}
+
+static void nf_conntrack_all_unlock(void)
+{
+       int i;
+
+       for (i = 0; i < CONNTRACK_LOCKS; i++)
+               spin_unlock(&nf_conntrack_locks[i]);
+}
 
 unsigned int nf_conntrack_htable_size __read_mostly;
 EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
@@ -192,6 +243,50 @@ clean_from_lists(struct nf_conn *ct)
        nf_ct_remove_expectations(ct);
 }
 
+/* must be called with local_bh_disable */
+static void nf_ct_add_to_dying_list(struct nf_conn *ct)
+{
+       struct ct_pcpu *pcpu;
+
+       /* add this conntrack to the (per cpu) dying list */
+       ct->cpu = smp_processor_id();
+       pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu);
+
+       spin_lock(&pcpu->lock);
+       hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+                            &pcpu->dying);
+       spin_unlock(&pcpu->lock);
+}
+
+/* must be called with local_bh_disable */
+static void nf_ct_add_to_unconfirmed_list(struct nf_conn *ct)
+{
+       struct ct_pcpu *pcpu;
+
+       /* add this conntrack to the (per cpu) unconfirmed list */
+       ct->cpu = smp_processor_id();
+       pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu);
+
+       spin_lock(&pcpu->lock);
+       hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+                            &pcpu->unconfirmed);
+       spin_unlock(&pcpu->lock);
+}
+
+/* must be called with local_bh_disable */
+static void nf_ct_del_from_dying_or_unconfirmed_list(struct nf_conn *ct)
+{
+       struct ct_pcpu *pcpu;
+
+       /* We overload first tuple to link into unconfirmed or dying list.*/
+       pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu);
+
+       spin_lock(&pcpu->lock);
+       BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode));
+       hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
+       spin_unlock(&pcpu->lock);
+}
+
 static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
@@ -203,9 +298,6 @@ destroy_conntrack(struct nf_conntrack *nfct)
        NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
        NF_CT_ASSERT(!timer_pending(&ct->timeout));
 
-       /* To make sure we don't get any weird locking issues here:
-        * destroy_conntrack() MUST NOT be called with a write lock
-        * to nf_conntrack_lock!!! -HW */
        rcu_read_lock();
        l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
        if (l4proto && l4proto->destroy)
@@ -213,19 +305,18 @@ destroy_conntrack(struct nf_conntrack *nfct)
 
        rcu_read_unlock();
 
-       spin_lock_bh(&nf_conntrack_lock);
+       local_bh_disable();
        /* Expectations will have been removed in clean_from_lists,
         * except TFTP can create an expectation on the first packet,
         * before connection is in the list, so we need to clean here,
-        * too. */
+        * too.
+        */
        nf_ct_remove_expectations(ct);
 
-       /* We overload first tuple to link into unconfirmed or dying list.*/
-       BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode));
-       hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
+       nf_ct_del_from_dying_or_unconfirmed_list(ct);
 
        NF_CT_STAT_INC(net, delete);
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
 
        if (ct->master)
                nf_ct_put(ct->master);
@@ -237,17 +328,28 @@ destroy_conntrack(struct nf_conntrack *nfct)
 static void nf_ct_delete_from_lists(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
+       unsigned int hash, reply_hash;
+       u16 zone = nf_ct_zone(ct);
+       unsigned int sequence;
 
        nf_ct_helper_destroy(ct);
-       spin_lock_bh(&nf_conntrack_lock);
-       /* Inside lock so preempt is disabled on module removal path.
-        * Otherwise we can get spurious warnings. */
-       NF_CT_STAT_INC(net, delete_list);
+
+       local_bh_disable();
+       do {
+               sequence = read_seqcount_begin(&net->ct.generation);
+               hash = hash_conntrack(net, zone,
+                                     &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+               reply_hash = hash_conntrack(net, zone,
+                                          &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+       } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence));
+
        clean_from_lists(ct);
-       /* add this conntrack to the dying list */
-       hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-                            &net->ct.dying);
-       spin_unlock_bh(&nf_conntrack_lock);
+       nf_conntrack_double_unlock(hash, reply_hash);
+
+       nf_ct_add_to_dying_list(ct);
+
+       NF_CT_STAT_INC(net, delete_list);
+       local_bh_enable();
 }
 
 static void death_by_event(unsigned long ul_conntrack)
@@ -331,8 +433,6 @@ nf_ct_key_equal(struct nf_conntrack_tuple_hash *h,
  * Warning :
  * - Caller must take a reference on returned object
  *   and recheck nf_ct_tuple_equal(tuple, &h->tuple)
- * OR
- * - Caller must lock nf_conntrack_lock before calling this function
  */
 static struct nf_conntrack_tuple_hash *
 ____nf_conntrack_find(struct net *net, u16 zone,
@@ -408,32 +508,36 @@ EXPORT_SYMBOL_GPL(nf_conntrack_find_get);
 
 static void __nf_conntrack_hash_insert(struct nf_conn *ct,
                                       unsigned int hash,
-                                      unsigned int repl_hash)
+                                      unsigned int reply_hash)
 {
        struct net *net = nf_ct_net(ct);
 
        hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
                           &net->ct.hash[hash]);
        hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode,
-                          &net->ct.hash[repl_hash]);
+                          &net->ct.hash[reply_hash]);
 }
 
 int
 nf_conntrack_hash_check_insert(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
-       unsigned int hash, repl_hash;
+       unsigned int hash, reply_hash;
        struct nf_conntrack_tuple_hash *h;
        struct hlist_nulls_node *n;
        u16 zone;
+       unsigned int sequence;
 
        zone = nf_ct_zone(ct);
-       hash = hash_conntrack(net, zone,
-                             &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-       repl_hash = hash_conntrack(net, zone,
-                                  &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
 
-       spin_lock_bh(&nf_conntrack_lock);
+       local_bh_disable();
+       do {
+               sequence = read_seqcount_begin(&net->ct.generation);
+               hash = hash_conntrack(net, zone,
+                                     &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+               reply_hash = hash_conntrack(net, zone,
+                                          &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+       } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence));
 
        /* See if there's one in the list already, including reverse */
        hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode)
@@ -441,7 +545,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
                                      &h->tuple) &&
                    zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
                        goto out;
-       hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode)
+       hlist_nulls_for_each_entry(h, n, &net->ct.hash[reply_hash], hnnode)
                if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
                                      &h->tuple) &&
                    zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
@@ -451,15 +555,16 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
        smp_wmb();
        /* The caller holds a reference to this object */
        atomic_set(&ct->ct_general.use, 2);
-       __nf_conntrack_hash_insert(ct, hash, repl_hash);
+       __nf_conntrack_hash_insert(ct, hash, reply_hash);
+       nf_conntrack_double_unlock(hash, reply_hash);
        NF_CT_STAT_INC(net, insert);
-       spin_unlock_bh(&nf_conntrack_lock);
-
+       local_bh_enable();
        return 0;
 
 out:
+       nf_conntrack_double_unlock(hash, reply_hash);
        NF_CT_STAT_INC(net, insert_failed);
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
        return -EEXIST;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
@@ -467,15 +572,22 @@ EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
 /* deletion from this larval template list happens via nf_ct_put() */
 void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl)
 {
+       struct ct_pcpu *pcpu;
+
        __set_bit(IPS_TEMPLATE_BIT, &tmpl->status);
        __set_bit(IPS_CONFIRMED_BIT, &tmpl->status);
        nf_conntrack_get(&tmpl->ct_general);
 
-       spin_lock_bh(&nf_conntrack_lock);
+       /* add this conntrack to the (per cpu) tmpl list */
+       local_bh_disable();
+       tmpl->cpu = smp_processor_id();
+       pcpu = per_cpu_ptr(nf_ct_net(tmpl)->ct.pcpu_lists, tmpl->cpu);
+
+       spin_lock(&pcpu->lock);
        /* Overload tuple linked list to put us in template list. */
        hlist_nulls_add_head_rcu(&tmpl->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-                                &net->ct.tmpl);
-       spin_unlock_bh(&nf_conntrack_lock);
+                                &pcpu->tmpl);
+       spin_unlock_bh(&pcpu->lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert);
 
@@ -483,7 +595,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert);
 int
 __nf_conntrack_confirm(struct sk_buff *skb)
 {
-       unsigned int hash, repl_hash;
+       unsigned int hash, reply_hash;
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct;
        struct nf_conn_help *help;
@@ -492,6 +604,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        enum ip_conntrack_info ctinfo;
        struct net *net;
        u16 zone;
+       unsigned int sequence;
 
        ct = nf_ct_get(skb, &ctinfo);
        net = nf_ct_net(ct);
@@ -504,31 +617,37 @@ __nf_conntrack_confirm(struct sk_buff *skb)
                return NF_ACCEPT;
 
        zone = nf_ct_zone(ct);
-       /* reuse the hash saved before */
-       hash = *(unsigned long *)&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev;
-       hash = hash_bucket(hash, net);
-       repl_hash = hash_conntrack(net, zone,
-                                  &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+       local_bh_disable();
+
+       do {
+               sequence = read_seqcount_begin(&net->ct.generation);
+               /* reuse the hash saved before */
+               hash = *(unsigned long *)&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev;
+               hash = hash_bucket(hash, net);
+               reply_hash = hash_conntrack(net, zone,
+                                          &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+
+       } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence));
 
        /* We're not in hash table, and we refuse to set up related
-          connections for unconfirmed conns.  But packet copies and
-          REJECT will give spurious warnings here. */
+        * connections for unconfirmed conns.  But packet copies and
+        * REJECT will give spurious warnings here.
+        */
        /* NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
 
        /* No external references means no one else could have
-          confirmed us. */
+        * confirmed us.
+        */
        NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
        pr_debug("Confirming conntrack %p\n", ct);
-
-       spin_lock_bh(&nf_conntrack_lock);
-
        /* We have to check the DYING flag inside the lock to prevent
           a race against nf_ct_get_next_corpse() possibly called from
           user context, else we insert an already 'dead' hash, blocking
           further use of that particular connection -JM */
 
        if (unlikely(nf_ct_is_dying(ct))) {
-               spin_unlock_bh(&nf_conntrack_lock);
+               nf_conntrack_double_unlock(hash, reply_hash);
+               local_bh_enable();
                return NF_ACCEPT;
        }
 
@@ -540,14 +659,13 @@ __nf_conntrack_confirm(struct sk_buff *skb)
                                      &h->tuple) &&
                    zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
                        goto out;
-       hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode)
+       hlist_nulls_for_each_entry(h, n, &net->ct.hash[reply_hash], hnnode)
                if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
                                      &h->tuple) &&
                    zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
                        goto out;
 
-       /* Remove from unconfirmed list */
-       hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
+       nf_ct_del_from_dying_or_unconfirmed_list(ct);
 
        /* Timer relative to confirmation time, not original
           setting time, otherwise we'd get timer wrap in
@@ -570,9 +688,10 @@ __nf_conntrack_confirm(struct sk_buff *skb)
         * guarantee that no other CPU can find the conntrack before the above
         * stores are visible.
         */
-       __nf_conntrack_hash_insert(ct, hash, repl_hash);
+       __nf_conntrack_hash_insert(ct, hash, reply_hash);
+       nf_conntrack_double_unlock(hash, reply_hash);
        NF_CT_STAT_INC(net, insert);
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
 
        help = nfct_help(ct);
        if (help && help->helper)
@@ -583,8 +702,9 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        return NF_ACCEPT;
 
 out:
+       nf_conntrack_double_unlock(hash, reply_hash);
        NF_CT_STAT_INC(net, insert_failed);
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
        return NF_DROP;
 }
 EXPORT_SYMBOL_GPL(__nf_conntrack_confirm);
@@ -627,39 +747,48 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken);
 
 /* There's a small race here where we may free a just-assured
    connection.  Too bad: we're in trouble anyway. */
-static noinline int early_drop(struct net *net, unsigned int hash)
+static noinline int early_drop(struct net *net, unsigned int _hash)
 {
        /* Use oldest entry, which is roughly LRU */
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct = NULL, *tmp;
        struct hlist_nulls_node *n;
-       unsigned int i, cnt = 0;
+       unsigned int i = 0, cnt = 0;
        int dropped = 0;
+       unsigned int hash, sequence;
+       spinlock_t *lockp;
 
-       rcu_read_lock();
-       for (i = 0; i < net->ct.htable_size; i++) {
+       local_bh_disable();
+restart:
+       sequence = read_seqcount_begin(&net->ct.generation);
+       hash = hash_bucket(_hash, net);
+       for (; i < net->ct.htable_size; i++) {
+               lockp = &nf_conntrack_locks[hash % CONNTRACK_LOCKS];
+               spin_lock(lockp);
+               if (read_seqcount_retry(&net->ct.generation, sequence)) {
+                       spin_unlock(lockp);
+                       goto restart;
+               }
                hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash],
                                         hnnode) {
                        tmp = nf_ct_tuplehash_to_ctrack(h);
-                       if (!test_bit(IPS_ASSURED_BIT, &tmp->status))
+                       if (!test_bit(IPS_ASSURED_BIT, &tmp->status) &&
+                           !nf_ct_is_dying(tmp) &&
+                           atomic_inc_not_zero(&tmp->ct_general.use)) {
                                ct = tmp;
+                               break;
+                       }
                        cnt++;
                }
 
-               if (ct != NULL) {
-                       if (likely(!nf_ct_is_dying(ct) &&
-                                  atomic_inc_not_zero(&ct->ct_general.use)))
-                               break;
-                       else
-                               ct = NULL;
-               }
+               hash = (hash + 1) % net->ct.htable_size;
+               spin_unlock(lockp);
 
-               if (cnt >= NF_CT_EVICTION_RANGE)
+               if (ct || cnt >= NF_CT_EVICTION_RANGE)
                        break;
 
-               hash = (hash + 1) % net->ct.htable_size;
        }
-       rcu_read_unlock();
+       local_bh_enable();
 
        if (!ct)
                return dropped;
@@ -708,7 +837,7 @@ __nf_conntrack_alloc(struct net *net, u16 zone,
 
        if (nf_conntrack_max &&
            unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) {
-               if (!early_drop(net, hash_bucket(hash, net))) {
+               if (!early_drop(net, hash)) {
                        atomic_dec(&net->ct.count);
                        net_warn_ratelimited("nf_conntrack: table full, dropping packet\n");
                        return ERR_PTR(-ENOMEM);
@@ -805,7 +934,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
        struct nf_conn_help *help;
        struct nf_conntrack_tuple repl_tuple;
        struct nf_conntrack_ecache *ecache;
-       struct nf_conntrack_expect *exp;
+       struct nf_conntrack_expect *exp = NULL;
        u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
        struct nf_conn_timeout *timeout_ext;
        unsigned int *timeouts;
@@ -849,42 +978,44 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
                                 ecache ? ecache->expmask : 0,
                             GFP_ATOMIC);
 
-       spin_lock_bh(&nf_conntrack_lock);
-       exp = nf_ct_find_expectation(net, zone, tuple);
-       if (exp) {
-               pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
-                        ct, exp);
-               /* Welcome, Mr. Bond.  We've been expecting you... */
-               __set_bit(IPS_EXPECTED_BIT, &ct->status);
-               ct->master = exp->master;
-               if (exp->helper) {
-                       help = nf_ct_helper_ext_add(ct, exp->helper,
-                                                   GFP_ATOMIC);
-                       if (help)
-                               rcu_assign_pointer(help->helper, exp->helper);
-               }
+       local_bh_disable();
+       if (net->ct.expect_count) {
+               spin_lock(&nf_conntrack_expect_lock);
+               exp = nf_ct_find_expectation(net, zone, tuple);
+               if (exp) {
+                       pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
+                                ct, exp);
+                       /* Welcome, Mr. Bond.  We've been expecting you... */
+                       __set_bit(IPS_EXPECTED_BIT, &ct->status);
+                       /* exp->master safe, refcnt bumped in nf_ct_find_expectation */
+                       ct->master = exp->master;
+                       if (exp->helper) {
+                               help = nf_ct_helper_ext_add(ct, exp->helper,
+                                                           GFP_ATOMIC);
+                               if (help)
+                                       rcu_assign_pointer(help->helper, exp->helper);
+                       }
 
 #ifdef CONFIG_NF_CONNTRACK_MARK
-               ct->mark = exp->master->mark;
+                       ct->mark = exp->master->mark;
 #endif
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
-               ct->secmark = exp->master->secmark;
+                       ct->secmark = exp->master->secmark;
 #endif
-               nf_conntrack_get(&ct->master->ct_general);
-               NF_CT_STAT_INC(net, expect_new);
-       } else {
+                       NF_CT_STAT_INC(net, expect_new);
+               }
+               spin_unlock(&nf_conntrack_expect_lock);
+       }
+       if (!exp) {
                __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);
                NF_CT_STAT_INC(net, new);
        }
 
        /* Now it is inserted into the unconfirmed list, bump refcount */
        nf_conntrack_get(&ct->ct_general);
+       nf_ct_add_to_unconfirmed_list(ct);
 
-       /* Overload tuple linked list to put us in unconfirmed list. */
-       hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-                      &net->ct.unconfirmed);
-
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
 
        if (exp) {
                if (exp->expectfn)
@@ -1254,27 +1385,42 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data),
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct;
        struct hlist_nulls_node *n;
+       int cpu;
+       spinlock_t *lockp;
 
-       spin_lock_bh(&nf_conntrack_lock);
        for (; *bucket < net->ct.htable_size; (*bucket)++) {
-               hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) {
-                       if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
-                               continue;
+               lockp = &nf_conntrack_locks[*bucket % CONNTRACK_LOCKS];
+               local_bh_disable();
+               spin_lock(lockp);
+               if (*bucket < net->ct.htable_size) {
+                       hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) {
+                               if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
+                                       continue;
+                               ct = nf_ct_tuplehash_to_ctrack(h);
+                               if (iter(ct, data))
+                                       goto found;
+                       }
+               }
+               spin_unlock(lockp);
+               local_bh_enable();
+       }
+
+       for_each_possible_cpu(cpu) {
+               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+               spin_lock_bh(&pcpu->lock);
+               hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) {
                        ct = nf_ct_tuplehash_to_ctrack(h);
                        if (iter(ct, data))
-                               goto found;
+                               set_bit(IPS_DYING_BIT, &ct->status);
                }
+               spin_unlock_bh(&pcpu->lock);
        }
-       hlist_nulls_for_each_entry(h, n, &net->ct.unconfirmed, hnnode) {
-               ct = nf_ct_tuplehash_to_ctrack(h);
-               if (iter(ct, data))
-                       set_bit(IPS_DYING_BIT, &ct->status);
-       }
-       spin_unlock_bh(&nf_conntrack_lock);
        return NULL;
 found:
        atomic_inc(&ct->ct_general.use);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock(lockp);
+       local_bh_enable();
        return ct;
 }
 
@@ -1323,14 +1469,19 @@ static void nf_ct_release_dying_list(struct net *net)
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct;
        struct hlist_nulls_node *n;
+       int cpu;
 
-       spin_lock_bh(&nf_conntrack_lock);
-       hlist_nulls_for_each_entry(h, n, &net->ct.dying, hnnode) {
-               ct = nf_ct_tuplehash_to_ctrack(h);
-               /* never fails to remove them, no listeners at this point */
-               nf_ct_kill(ct);
+       for_each_possible_cpu(cpu) {
+               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+               spin_lock_bh(&pcpu->lock);
+               hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
+                       ct = nf_ct_tuplehash_to_ctrack(h);
+                       /* never fails to remove them, no listeners at this point */
+                       nf_ct_kill(ct);
+               }
+               spin_unlock_bh(&pcpu->lock);
        }
-       spin_unlock_bh(&nf_conntrack_lock);
 }
 
 static int untrack_refs(void)
@@ -1417,6 +1568,7 @@ i_see_dead_people:
                kmem_cache_destroy(net->ct.nf_conntrack_cachep);
                kfree(net->ct.slabname);
                free_percpu(net->ct.stat);
+               free_percpu(net->ct.pcpu_lists);
        }
 }
 
@@ -1469,12 +1621,16 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
        if (!hash)
                return -ENOMEM;
 
+       local_bh_disable();
+       nf_conntrack_all_lock();
+       write_seqcount_begin(&init_net.ct.generation);
+
        /* Lookups in the old hash might happen in parallel, which means we
         * might get false negatives during connection lookup. New connections
         * created because of a false negative won't make it into the hash
-        * though since that required taking the lock.
+        * though since that required taking the locks.
         */
-       spin_lock_bh(&nf_conntrack_lock);
+
        for (i = 0; i < init_net.ct.htable_size; i++) {
                while (!hlist_nulls_empty(&init_net.ct.hash[i])) {
                        h = hlist_nulls_entry(init_net.ct.hash[i].first,
@@ -1491,7 +1647,10 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
 
        init_net.ct.htable_size = nf_conntrack_htable_size = hashsize;
        init_net.ct.hash = hash;
-       spin_unlock_bh(&nf_conntrack_lock);
+
+       write_seqcount_end(&init_net.ct.generation);
+       nf_conntrack_all_unlock();
+       local_bh_enable();
 
        nf_ct_free_hashtable(old_hash, old_size);
        return 0;
@@ -1513,7 +1672,10 @@ EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
 int nf_conntrack_init_start(void)
 {
        int max_factor = 8;
-       int ret, cpu;
+       int i, ret, cpu;
+
+       for (i = 0; i < CONNTRACK_LOCKS; i++)
+               spin_lock_init(&nf_conntrack_locks[i]);
 
        /* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
         * machine has 512 buckets. >= 1GB machines have 16384 buckets. */
@@ -1629,37 +1791,43 @@ void nf_conntrack_init_end(void)
 
 int nf_conntrack_init_net(struct net *net)
 {
-       int ret;
+       int ret = -ENOMEM;
+       int cpu;
 
        atomic_set(&net->ct.count, 0);
-       INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, UNCONFIRMED_NULLS_VAL);
-       INIT_HLIST_NULLS_HEAD(&net->ct.dying, DYING_NULLS_VAL);
-       INIT_HLIST_NULLS_HEAD(&net->ct.tmpl, TEMPLATE_NULLS_VAL);
-       net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
-       if (!net->ct.stat) {
-               ret = -ENOMEM;
+
+       net->ct.pcpu_lists = alloc_percpu(struct ct_pcpu);
+       if (!net->ct.pcpu_lists)
                goto err_stat;
+
+       for_each_possible_cpu(cpu) {
+               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+               spin_lock_init(&pcpu->lock);
+               INIT_HLIST_NULLS_HEAD(&pcpu->unconfirmed, UNCONFIRMED_NULLS_VAL);
+               INIT_HLIST_NULLS_HEAD(&pcpu->dying, DYING_NULLS_VAL);
+               INIT_HLIST_NULLS_HEAD(&pcpu->tmpl, TEMPLATE_NULLS_VAL);
        }
 
+       net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
+       if (!net->ct.stat)
+               goto err_pcpu_lists;
+
        net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%p", net);
-       if (!net->ct.slabname) {
-               ret = -ENOMEM;
+       if (!net->ct.slabname)
                goto err_slabname;
-       }
 
        net->ct.nf_conntrack_cachep = kmem_cache_create(net->ct.slabname,
                                                        sizeof(struct nf_conn), 0,
                                                        SLAB_DESTROY_BY_RCU, NULL);
        if (!net->ct.nf_conntrack_cachep) {
                printk(KERN_ERR "Unable to create nf_conn slab cache\n");
-               ret = -ENOMEM;
                goto err_cache;
        }
 
        net->ct.htable_size = nf_conntrack_htable_size;
        net->ct.hash = nf_ct_alloc_hashtable(&net->ct.htable_size, 1);
        if (!net->ct.hash) {
-               ret = -ENOMEM;
                printk(KERN_ERR "Unable to create nf_conntrack_hash\n");
                goto err_hash;
        }
@@ -1701,6 +1869,8 @@ err_cache:
        kfree(net->ct.slabname);
 err_slabname:
        free_percpu(net->ct.stat);
+err_pcpu_lists:
+       free_percpu(net->ct.pcpu_lists);
 err_stat:
        return ret;
 }
index 4fd1ca94fd4a140b374385ded878af60b503b529..f87e8f68ad453e9baeec017cc74534e8ce85dfab 100644 (file)
@@ -66,9 +66,9 @@ static void nf_ct_expectation_timed_out(unsigned long ul_expect)
 {
        struct nf_conntrack_expect *exp = (void *)ul_expect;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        nf_ct_unlink_expect(exp);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
        nf_ct_expect_put(exp);
 }
 
@@ -155,6 +155,18 @@ nf_ct_find_expectation(struct net *net, u16 zone,
        if (!nf_ct_is_confirmed(exp->master))
                return NULL;
 
+       /* Avoid race with other CPUs, that for exp->master ct, is
+        * about to invoke ->destroy(), or nf_ct_delete() via timeout
+        * or early_drop().
+        *
+        * The atomic_inc_not_zero() check tells:  If that fails, we
+        * know that the ct is being destroyed.  If it succeeds, we
+        * can be sure the ct cannot disappear underneath.
+        */
+       if (unlikely(nf_ct_is_dying(exp->master) ||
+                    !atomic_inc_not_zero(&exp->master->ct_general.use)))
+               return NULL;
+
        if (exp->flags & NF_CT_EXPECT_PERMANENT) {
                atomic_inc(&exp->use);
                return exp;
@@ -162,6 +174,8 @@ nf_ct_find_expectation(struct net *net, u16 zone,
                nf_ct_unlink_expect(exp);
                return exp;
        }
+       /* Undo exp->master refcnt increase, if del_timer() failed */
+       nf_ct_put(exp->master);
 
        return NULL;
 }
@@ -177,12 +191,14 @@ void nf_ct_remove_expectations(struct nf_conn *ct)
        if (!help)
                return;
 
+       spin_lock_bh(&nf_conntrack_expect_lock);
        hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
                if (del_timer(&exp->timeout)) {
                        nf_ct_unlink_expect(exp);
                        nf_ct_expect_put(exp);
                }
        }
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_remove_expectations);
 
@@ -217,12 +233,12 @@ static inline int expect_matches(const struct nf_conntrack_expect *a,
 /* Generally a bad idea to call this: could have matched already. */
 void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
 {
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        if (del_timer(&exp->timeout)) {
                nf_ct_unlink_expect(exp);
                nf_ct_expect_put(exp);
        }
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
 
@@ -335,7 +351,7 @@ static int nf_ct_expect_insert(struct nf_conntrack_expect *exp)
        setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
                    (unsigned long)exp);
        helper = rcu_dereference_protected(master_help->helper,
-                                          lockdep_is_held(&nf_conntrack_lock));
+                                          lockdep_is_held(&nf_conntrack_expect_lock));
        if (helper) {
                exp->timeout.expires = jiffies +
                        helper->expect_policy[exp->class].timeout * HZ;
@@ -395,7 +411,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
        }
        /* Will be over limit? */
        helper = rcu_dereference_protected(master_help->helper,
-                                          lockdep_is_held(&nf_conntrack_lock));
+                                          lockdep_is_held(&nf_conntrack_expect_lock));
        if (helper) {
                p = &helper->expect_policy[expect->class];
                if (p->max_expected &&
@@ -417,12 +433,12 @@ out:
        return ret;
 }
 
-int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, 
+int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
                                u32 portid, int report)
 {
        int ret;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        ret = __nf_ct_expect_check(expect);
        if (ret <= 0)
                goto out;
@@ -430,11 +446,11 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
        ret = nf_ct_expect_insert(expect);
        if (ret < 0)
                goto out;
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
        nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
        return ret;
 out:
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
index 70866d192efc9351f2fcafe3ef23ce0c131fc0ba..3a3a60b126e0097f309badc40ebf8016b3773c98 100644 (file)
@@ -1476,7 +1476,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
                nf_ct_refresh(ct, skb, info->timeout * HZ);
 
                /* Set expect timeout */
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                exp = find_expect(ct, &ct->tuplehash[dir].tuple.dst.u3,
                                  info->sig_port[!dir]);
                if (exp) {
@@ -1486,7 +1486,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
                        nf_ct_dump_tuple(&exp->tuple);
                        set_expect_timeout(exp, info->timeout);
                }
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
        }
 
        return 0;
index 974a2a4adefa739c729692e0df3ad3142f83d0d4..5b3eae7d4c9a51dd1bdd559fa5943125035d8490 100644 (file)
@@ -250,16 +250,14 @@ out:
 }
 EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
 
+/* appropiate ct lock protecting must be taken by caller */
 static inline int unhelp(struct nf_conntrack_tuple_hash *i,
                         const struct nf_conntrack_helper *me)
 {
        struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i);
        struct nf_conn_help *help = nfct_help(ct);
 
-       if (help && rcu_dereference_protected(
-                       help->helper,
-                       lockdep_is_held(&nf_conntrack_lock)
-                       ) == me) {
+       if (help && rcu_dereference_raw(help->helper) == me) {
                nf_conntrack_event(IPCT_HELPER, ct);
                RCU_INIT_POINTER(help->helper, NULL);
        }
@@ -284,17 +282,17 @@ static LIST_HEAD(nf_ct_helper_expectfn_list);
 
 void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n)
 {
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        list_add_rcu(&n->head, &nf_ct_helper_expectfn_list);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register);
 
 void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n)
 {
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        list_del_rcu(&n->head);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
 
@@ -396,15 +394,17 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
        const struct hlist_node *next;
        const struct hlist_nulls_node *nn;
        unsigned int i;
+       int cpu;
 
        /* Get rid of expectations */
+       spin_lock_bh(&nf_conntrack_expect_lock);
        for (i = 0; i < nf_ct_expect_hsize; i++) {
                hlist_for_each_entry_safe(exp, next,
                                          &net->ct.expect_hash[i], hnode) {
                        struct nf_conn_help *help = nfct_help(exp->master);
                        if ((rcu_dereference_protected(
                                        help->helper,
-                                       lockdep_is_held(&nf_conntrack_lock)
+                                       lockdep_is_held(&nf_conntrack_expect_lock)
                                        ) == me || exp->helper == me) &&
                            del_timer(&exp->timeout)) {
                                nf_ct_unlink_expect(exp);
@@ -412,14 +412,27 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
                        }
                }
        }
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 
        /* Get rid of expecteds, set helpers to NULL. */
-       hlist_nulls_for_each_entry(h, nn, &net->ct.unconfirmed, hnnode)
-               unhelp(h, me);
-       for (i = 0; i < net->ct.htable_size; i++) {
-               hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode)
+       for_each_possible_cpu(cpu) {
+               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+               spin_lock_bh(&pcpu->lock);
+               hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode)
                        unhelp(h, me);
+               spin_unlock_bh(&pcpu->lock);
+       }
+       local_bh_disable();
+       for (i = 0; i < net->ct.htable_size; i++) {
+               spin_lock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]);
+               if (i < net->ct.htable_size) {
+                       hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode)
+                               unhelp(h, me);
+               }
+               spin_unlock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]);
        }
+       local_bh_enable();
 }
 
 void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
@@ -437,10 +450,8 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
        synchronize_rcu();
 
        rtnl_lock();
-       spin_lock_bh(&nf_conntrack_lock);
        for_each_net(net)
                __nf_conntrack_helper_unregister(me, net);
-       spin_unlock_bh(&nf_conntrack_lock);
        rtnl_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
index bb322d0beb484f3c66a334a5e0b24651f2a1ffca..ccc46fa5edbce5e52710a22ae502e49a0f59e0a5 100644 (file)
@@ -764,14 +764,23 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
        struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
        u_int8_t l3proto = nfmsg->nfgen_family;
        int res;
+       spinlock_t *lockp;
+
 #ifdef CONFIG_NF_CONNTRACK_MARK
        const struct ctnetlink_dump_filter *filter = cb->data;
 #endif
 
-       spin_lock_bh(&nf_conntrack_lock);
        last = (struct nf_conn *)cb->args[1];
+
+       local_bh_disable();
        for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) {
 restart:
+               lockp = &nf_conntrack_locks[cb->args[0] % CONNTRACK_LOCKS];
+               spin_lock(lockp);
+               if (cb->args[0] >= net->ct.htable_size) {
+                       spin_unlock(lockp);
+                       goto out;
+               }
                hlist_nulls_for_each_entry(h, n, &net->ct.hash[cb->args[0]],
                                         hnnode) {
                        if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
@@ -803,16 +812,18 @@ restart:
                        if (res < 0) {
                                nf_conntrack_get(&ct->ct_general);
                                cb->args[1] = (unsigned long)ct;
+                               spin_unlock(lockp);
                                goto out;
                        }
                }
+               spin_unlock(lockp);
                if (cb->args[1]) {
                        cb->args[1] = 0;
                        goto restart;
                }
        }
 out:
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
        if (last)
                nf_ct_put(last);
 
@@ -966,7 +977,6 @@ ctnetlink_parse_help(const struct nlattr *attr, char **helper_name,
        return 0;
 }
 
-#define __CTA_LABELS_MAX_LENGTH ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE)
 static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
        [CTA_TUPLE_ORIG]        = { .type = NLA_NESTED },
        [CTA_TUPLE_REPLY]       = { .type = NLA_NESTED },
@@ -984,9 +994,9 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
        [CTA_ZONE]              = { .type = NLA_U16 },
        [CTA_MARK_MASK]         = { .type = NLA_U32 },
        [CTA_LABELS]            = { .type = NLA_BINARY,
-                                   .len = __CTA_LABELS_MAX_LENGTH },
+                                   .len = NF_CT_LABELS_MAX_SIZE },
        [CTA_LABELS_MASK]       = { .type = NLA_BINARY,
-                                   .len = __CTA_LABELS_MAX_LENGTH },
+                                   .len = NF_CT_LABELS_MAX_SIZE },
 };
 
 static int
@@ -1138,50 +1148,65 @@ static int ctnetlink_done_list(struct netlink_callback *cb)
 }
 
 static int
-ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb,
-                   struct hlist_nulls_head *list)
+ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying)
 {
-       struct nf_conn *ct, *last;
+       struct nf_conn *ct, *last = NULL;
        struct nf_conntrack_tuple_hash *h;
        struct hlist_nulls_node *n;
        struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
        u_int8_t l3proto = nfmsg->nfgen_family;
        int res;
+       int cpu;
+       struct hlist_nulls_head *list;
+       struct net *net = sock_net(skb->sk);
 
        if (cb->args[2])
                return 0;
 
-       spin_lock_bh(&nf_conntrack_lock);
-       last = (struct nf_conn *)cb->args[1];
-restart:
-       hlist_nulls_for_each_entry(h, n, list, hnnode) {
-               ct = nf_ct_tuplehash_to_ctrack(h);
-               if (l3proto && nf_ct_l3num(ct) != l3proto)
+       if (cb->args[0] == nr_cpu_ids)
+               return 0;
+
+       for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
+               struct ct_pcpu *pcpu;
+
+               if (!cpu_possible(cpu))
                        continue;
-               if (cb->args[1]) {
-                       if (ct != last)
+
+               pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+               spin_lock_bh(&pcpu->lock);
+               last = (struct nf_conn *)cb->args[1];
+               list = dying ? &pcpu->dying : &pcpu->unconfirmed;
+restart:
+               hlist_nulls_for_each_entry(h, n, list, hnnode) {
+                       ct = nf_ct_tuplehash_to_ctrack(h);
+                       if (l3proto && nf_ct_l3num(ct) != l3proto)
                                continue;
-                       cb->args[1] = 0;
-               }
-               rcu_read_lock();
-               res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
-                                         cb->nlh->nlmsg_seq,
-                                         NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
-                                         ct);
-               rcu_read_unlock();
-               if (res < 0) {
-                       nf_conntrack_get(&ct->ct_general);
-                       cb->args[1] = (unsigned long)ct;
-                       goto out;
+                       if (cb->args[1]) {
+                               if (ct != last)
+                                       continue;
+                               cb->args[1] = 0;
+                       }
+                       rcu_read_lock();
+                       res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
+                                                 cb->nlh->nlmsg_seq,
+                                                 NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
+                                                 ct);
+                       rcu_read_unlock();
+                       if (res < 0) {
+                               nf_conntrack_get(&ct->ct_general);
+                               cb->args[1] = (unsigned long)ct;
+                               spin_unlock_bh(&pcpu->lock);
+                               goto out;
+                       }
                }
+               if (cb->args[1]) {
+                       cb->args[1] = 0;
+                       goto restart;
+               } else
+                       cb->args[2] = 1;
+               spin_unlock_bh(&pcpu->lock);
        }
-       if (cb->args[1]) {
-               cb->args[1] = 0;
-               goto restart;
-       } else
-               cb->args[2] = 1;
 out:
-       spin_unlock_bh(&nf_conntrack_lock);
        if (last)
                nf_ct_put(last);
 
@@ -1191,9 +1216,7 @@ out:
 static int
 ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct net *net = sock_net(skb->sk);
-
-       return ctnetlink_dump_list(skb, cb, &net->ct.dying);
+       return ctnetlink_dump_list(skb, cb, true);
 }
 
 static int
@@ -1215,9 +1238,7 @@ ctnetlink_get_ct_dying(struct sock *ctnl, struct sk_buff *skb,
 static int
 ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct net *net = sock_net(skb->sk);
-
-       return ctnetlink_dump_list(skb, cb, &net->ct.unconfirmed);
+       return ctnetlink_dump_list(skb, cb, false);
 }
 
 static int
@@ -1310,27 +1331,22 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
 }
 
 static int
-ctnetlink_change_nat(struct nf_conn *ct, const struct nlattr * const cda[])
+ctnetlink_setup_nat(struct nf_conn *ct, const struct nlattr * const cda[])
 {
 #ifdef CONFIG_NF_NAT_NEEDED
        int ret;
 
-       if (cda[CTA_NAT_DST]) {
-               ret = ctnetlink_parse_nat_setup(ct,
-                                               NF_NAT_MANIP_DST,
-                                               cda[CTA_NAT_DST]);
-               if (ret < 0)
-                       return ret;
-       }
-       if (cda[CTA_NAT_SRC]) {
-               ret = ctnetlink_parse_nat_setup(ct,
-                                               NF_NAT_MANIP_SRC,
-                                               cda[CTA_NAT_SRC]);
-               if (ret < 0)
-                       return ret;
-       }
-       return 0;
+       ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_DST,
+                                       cda[CTA_NAT_DST]);
+       if (ret < 0)
+               return ret;
+
+       ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_SRC,
+                                       cda[CTA_NAT_SRC]);
+       return ret;
 #else
+       if (!cda[CTA_NAT_DST] && !cda[CTA_NAT_SRC])
+               return 0;
        return -EOPNOTSUPP;
 #endif
 }
@@ -1366,14 +1382,14 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
                                            nf_ct_protonum(ct));
        if (helper == NULL) {
 #ifdef CONFIG_MODULES
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
 
                if (request_module("nfct-helper-%s", helpname) < 0) {
-                       spin_lock_bh(&nf_conntrack_lock);
+                       spin_lock_bh(&nf_conntrack_expect_lock);
                        return -EOPNOTSUPP;
                }
 
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
                                                    nf_ct_protonum(ct));
                if (helper)
@@ -1659,11 +1675,9 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
                        goto err2;
        }
 
-       if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
-               err = ctnetlink_change_nat(ct, cda);
-               if (err < 0)
-                       goto err2;
-       }
+       err = ctnetlink_setup_nat(ct, cda);
+       if (err < 0)
+               goto err2;
 
        nf_ct_acct_ext_add(ct, GFP_ATOMIC);
        nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
@@ -1811,9 +1825,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
        err = -EEXIST;
        ct = nf_ct_tuplehash_to_ctrack(h);
        if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                err = ctnetlink_change_conntrack(ct, cda);
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
                if (err == 0) {
                        nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
                                                      (1 << IPCT_ASSURED) |
@@ -2142,9 +2156,9 @@ ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
        if (ret < 0)
                return ret;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        ret = ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 
        return ret;
 }
@@ -2699,13 +2713,13 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                }
 
                /* after list removal, usage count == 1 */
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                if (del_timer(&exp->timeout)) {
                        nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
                                                   nlmsg_report(nlh));
                        nf_ct_expect_put(exp);
                }
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
                /* have to put what we 'get' above.
                 * after this line usage count == 0 */
                nf_ct_expect_put(exp);
@@ -2714,7 +2728,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                struct nf_conn_help *m_help;
 
                /* delete all expectations for this helper */
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                for (i = 0; i < nf_ct_expect_hsize; i++) {
                        hlist_for_each_entry_safe(exp, next,
                                                  &net->ct.expect_hash[i],
@@ -2729,10 +2743,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                                }
                        }
                }
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
        } else {
                /* This basically means we have to flush everything*/
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                for (i = 0; i < nf_ct_expect_hsize; i++) {
                        hlist_for_each_entry_safe(exp, next,
                                                  &net->ct.expect_hash[i],
@@ -2745,7 +2759,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                                }
                        }
                }
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
        }
 
        return 0;
@@ -2971,11 +2985,11 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        exp = __nf_ct_expect_find(net, zone, &tuple);
 
        if (!exp) {
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
                err = -ENOENT;
                if (nlh->nlmsg_flags & NLM_F_CREATE) {
                        err = ctnetlink_create_expect(net, zone, cda,
@@ -2989,7 +3003,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
        err = -EEXIST;
        if (!(nlh->nlmsg_flags & NLM_F_EXCL))
                err = ctnetlink_change_expect(exp, cda);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 
        return err;
 }
index 466410eaa482c2a3940d3768351e92be17a644ef..4c3ba1c8d682d16abe0912f80525a84d184130db 100644 (file)
@@ -800,7 +800,7 @@ static int refresh_signalling_expectation(struct nf_conn *ct,
        struct hlist_node *next;
        int found = 0;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
                if (exp->class != SIP_EXPECT_SIGNALLING ||
                    !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) ||
@@ -815,7 +815,7 @@ static int refresh_signalling_expectation(struct nf_conn *ct,
                found = 1;
                break;
        }
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
        return found;
 }
 
@@ -825,7 +825,7 @@ static void flush_expectations(struct nf_conn *ct, bool media)
        struct nf_conntrack_expect *exp;
        struct hlist_node *next;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
                if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media)
                        continue;
@@ -836,7 +836,7 @@ static void flush_expectations(struct nf_conn *ct, bool media)
                if (!media)
                        break;
        }
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 
 static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
index d3f5cd6dd962b195ea85775cd0432cf204e697b2..52ca952b802c5e3ea41c83823b90f74365b8fc76 100644 (file)
@@ -432,15 +432,15 @@ nf_nat_setup_info(struct nf_conn *ct,
 }
 EXPORT_SYMBOL(nf_nat_setup_info);
 
-unsigned int
-nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
+static unsigned int
+__nf_nat_alloc_null_binding(struct nf_conn *ct, enum nf_nat_manip_type manip)
 {
        /* Force range to this IP; let proto decide mapping for
         * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
         * Use reply in case it's already been mangled (eg local packet).
         */
        union nf_inet_addr ip =
-               (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
+               (manip == NF_NAT_MANIP_SRC ?
                ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3 :
                ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3);
        struct nf_nat_range range = {
@@ -448,7 +448,13 @@ nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
                .min_addr       = ip,
                .max_addr       = ip,
        };
-       return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
+       return nf_nat_setup_info(ct, &range, manip);
+}
+
+unsigned int
+nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
+{
+       return __nf_nat_alloc_null_binding(ct, HOOK2MANIP(hooknum));
 }
 EXPORT_SYMBOL_GPL(nf_nat_alloc_null_binding);
 
@@ -702,9 +708,9 @@ static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
 
 static int
 nfnetlink_parse_nat(const struct nlattr *nat,
-                   const struct nf_conn *ct, struct nf_nat_range *range)
+                   const struct nf_conn *ct, struct nf_nat_range *range,
+                   const struct nf_nat_l3proto *l3proto)
 {
-       const struct nf_nat_l3proto *l3proto;
        struct nlattr *tb[CTA_NAT_MAX+1];
        int err;
 
@@ -714,38 +720,46 @@ nfnetlink_parse_nat(const struct nlattr *nat,
        if (err < 0)
                return err;
 
-       rcu_read_lock();
-       l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
-       if (l3proto == NULL) {
-               err = -EAGAIN;
-               goto out;
-       }
        err = l3proto->nlattr_to_range(tb, range);
        if (err < 0)
-               goto out;
+               return err;
 
        if (!tb[CTA_NAT_PROTO])
-               goto out;
+               return 0;
 
-       err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
-out:
-       rcu_read_unlock();
-       return err;
+       return nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
 }
 
+/* This function is called under rcu_read_lock() */
 static int
 nfnetlink_parse_nat_setup(struct nf_conn *ct,
                          enum nf_nat_manip_type manip,
                          const struct nlattr *attr)
 {
        struct nf_nat_range range;
+       const struct nf_nat_l3proto *l3proto;
        int err;
 
-       err = nfnetlink_parse_nat(attr, ct, &range);
+       /* Should not happen, restricted to creating new conntracks
+        * via ctnetlink.
+        */
+       if (WARN_ON_ONCE(nf_nat_initialized(ct, manip)))
+               return -EEXIST;
+
+       /* Make sure that L3 NAT is there by when we call nf_nat_setup_info to
+        * attach the null binding, otherwise this may oops.
+        */
+       l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
+       if (l3proto == NULL)
+               return -EAGAIN;
+
+       /* No NAT information has been passed, allocate the null-binding */
+       if (attr == NULL)
+               return __nf_nat_alloc_null_binding(ct, manip);
+
+       err = nfnetlink_parse_nat(attr, ct, &range, l3proto);
        if (err < 0)
                return err;
-       if (nf_nat_initialized(ct, manip))
-               return -EEXIST;
 
        return nf_nat_setup_info(ct, &range, manip);
 }
index adce01e8bb57e7fb9794eebceae274707d96899e..33045a56229769502532b38e7b4a1bc5d89c80d8 100644 (file)
@@ -794,9 +794,8 @@ nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr)
        stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
 
        if (chain->stats) {
-               /* nfnl_lock is held, add some nfnl function for this, later */
                struct nft_stats __percpu *oldstats =
-                       rcu_dereference_protected(chain->stats, 1);
+                               nft_dereference(chain->stats);
 
                rcu_assign_pointer(chain->stats, newstats);
                synchronize_rcu();
@@ -1254,10 +1253,11 @@ err1:
        return err;
 }
 
-static void nf_tables_expr_destroy(struct nft_expr *expr)
+static void nf_tables_expr_destroy(const struct nft_ctx *ctx,
+                                  struct nft_expr *expr)
 {
        if (expr->ops->destroy)
-               expr->ops->destroy(expr);
+               expr->ops->destroy(ctx, expr);
        module_put(expr->ops->type->owner);
 }
 
@@ -1296,6 +1296,8 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
        [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
        [NFTA_RULE_COMPAT]      = { .type = NLA_NESTED },
        [NFTA_RULE_POSITION]    = { .type = NLA_U64 },
+       [NFTA_RULE_USERDATA]    = { .type = NLA_BINARY,
+                                   .len = NFT_USERDATA_MAXLEN },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1348,6 +1350,10 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
        }
        nla_nest_end(skb, list);
 
+       if (rule->ulen &&
+           nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule)))
+               goto nla_put_failure;
+
        return nlmsg_end(skb, nlh);
 
 nla_put_failure:
@@ -1531,7 +1537,8 @@ err:
        return err;
 }
 
-static void nf_tables_rule_destroy(struct nft_rule *rule)
+static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
+                                  struct nft_rule *rule)
 {
        struct nft_expr *expr;
 
@@ -1541,7 +1548,7 @@ static void nf_tables_rule_destroy(struct nft_rule *rule)
         */
        expr = nft_expr_first(rule);
        while (expr->ops && expr != nft_expr_last(rule)) {
-               nf_tables_expr_destroy(expr);
+               nf_tables_expr_destroy(ctx, expr);
                expr = nft_expr_next(expr);
        }
        kfree(rule);
@@ -1552,7 +1559,7 @@ static void nf_tables_rule_destroy(struct nft_rule *rule)
 static struct nft_expr_info *info;
 
 static struct nft_rule_trans *
-nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx)
+nf_tables_trans_add(struct nft_ctx *ctx, struct nft_rule *rule)
 {
        struct nft_rule_trans *rupd;
 
@@ -1560,11 +1567,8 @@ nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx)
        if (rupd == NULL)
               return NULL;
 
-       rupd->chain = ctx->chain;
-       rupd->table = ctx->table;
+       rupd->ctx = *ctx;
        rupd->rule = rule;
-       rupd->family = ctx->afi->family;
-       rupd->nlh = ctx->nlh;
        list_add_tail(&rupd->list, &ctx->net->nft.commit_list);
 
        return rupd;
@@ -1584,7 +1588,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
        struct nft_expr *expr;
        struct nft_ctx ctx;
        struct nlattr *tmp;
-       unsigned int size, i, n;
+       unsigned int size, i, n, ulen = 0;
        int err, rem;
        bool create;
        u64 handle, pos_handle;
@@ -1650,8 +1654,11 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
                }
        }
 
+       if (nla[NFTA_RULE_USERDATA])
+               ulen = nla_len(nla[NFTA_RULE_USERDATA]);
+
        err = -ENOMEM;
-       rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
+       rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL);
        if (rule == NULL)
                goto err1;
 
@@ -1659,6 +1666,10 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
        rule->handle = handle;
        rule->dlen   = size;
+       rule->ulen   = ulen;
+
+       if (ulen)
+               nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen);
 
        expr = nft_expr_first(rule);
        for (i = 0; i < n; i++) {
@@ -1671,7 +1682,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
        if (nlh->nlmsg_flags & NLM_F_REPLACE) {
                if (nft_rule_is_active_next(net, old_rule)) {
-                       repl = nf_tables_trans_add(old_rule, &ctx);
+                       repl = nf_tables_trans_add(&ctx, old_rule);
                        if (repl == NULL) {
                                err = -ENOMEM;
                                goto err2;
@@ -1694,7 +1705,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
                        list_add_rcu(&rule->list, &chain->rules);
        }
 
-       if (nf_tables_trans_add(rule, &ctx) == NULL) {
+       if (nf_tables_trans_add(&ctx, rule) == NULL) {
                err = -ENOMEM;
                goto err3;
        }
@@ -1709,7 +1720,7 @@ err3:
                kfree(repl);
        }
 err2:
-       nf_tables_rule_destroy(rule);
+       nf_tables_rule_destroy(&ctx, rule);
 err1:
        for (i = 0; i < n; i++) {
                if (info[i].ops != NULL)
@@ -1723,7 +1734,7 @@ nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
 {
        /* You cannot delete the same rule twice */
        if (nft_rule_is_active_next(ctx->net, rule)) {
-               if (nf_tables_trans_add(rule, ctx) == NULL)
+               if (nf_tables_trans_add(ctx, rule) == NULL)
                        return -ENOMEM;
                nft_rule_disactivate_next(ctx->net, rule);
                return 0;
@@ -1819,10 +1830,10 @@ static int nf_tables_commit(struct sk_buff *skb)
                 */
                if (nft_rule_is_active(net, rupd->rule)) {
                        nft_rule_clear(net, rupd->rule);
-                       nf_tables_rule_notify(skb, rupd->nlh, rupd->table,
-                                             rupd->chain, rupd->rule,
-                                             NFT_MSG_NEWRULE, 0,
-                                             rupd->family);
+                       nf_tables_rule_notify(skb, rupd->ctx.nlh,
+                                             rupd->ctx.table, rupd->ctx.chain,
+                                             rupd->rule, NFT_MSG_NEWRULE, 0,
+                                             rupd->ctx.afi->family);
                        list_del(&rupd->list);
                        kfree(rupd);
                        continue;
@@ -1830,9 +1841,10 @@ static int nf_tables_commit(struct sk_buff *skb)
 
                /* This rule is in the past, get rid of it */
                list_del_rcu(&rupd->rule->list);
-               nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain,
+               nf_tables_rule_notify(skb, rupd->ctx.nlh,
+                                     rupd->ctx.table, rupd->ctx.chain,
                                      rupd->rule, NFT_MSG_DELRULE, 0,
-                                     rupd->family);
+                                     rupd->ctx.afi->family);
        }
 
        /* Make sure we don't see any packet traversing old rules */
@@ -1840,7 +1852,7 @@ static int nf_tables_commit(struct sk_buff *skb)
 
        /* Now we can safely release unused old rules */
        list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
-               nf_tables_rule_destroy(rupd->rule);
+               nf_tables_rule_destroy(&rupd->ctx, rupd->rule);
                list_del(&rupd->list);
                kfree(rupd);
        }
@@ -1869,7 +1881,7 @@ static int nf_tables_abort(struct sk_buff *skb)
        synchronize_rcu();
 
        list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
-               nf_tables_rule_destroy(rupd->rule);
+               nf_tables_rule_destroy(&rupd->ctx, rupd->rule);
                list_del(&rupd->list);
                kfree(rupd);
        }
@@ -2430,8 +2442,7 @@ err1:
 static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
 {
        list_del(&set->list);
-       if (!(set->flags & NFT_SET_ANONYMOUS))
-               nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
+       nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
 
        set->ops->destroy(set);
        module_put(set->ops->owner);
@@ -3175,9 +3186,16 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
        data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
 
        switch (data->verdict) {
-       case NF_ACCEPT:
-       case NF_DROP:
-       case NF_QUEUE:
+       default:
+               switch (data->verdict & NF_VERDICT_MASK) {
+               case NF_ACCEPT:
+               case NF_DROP:
+               case NF_QUEUE:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               /* fall through */
        case NFT_CONTINUE:
        case NFT_BREAK:
        case NFT_RETURN:
@@ -3198,8 +3216,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
                data->chain = chain;
                desc->len = sizeof(data);
                break;
-       default:
-               return -EINVAL;
        }
 
        desc->type = NFT_DATA_VERDICT;
index 046aa13b4fea6a570b990444b7ca4c6419824f8f..e8138da4c14f70f40449c72ec4dc4d31f2960b8e 100644 (file)
@@ -61,6 +61,14 @@ void nfnl_unlock(__u8 subsys_id)
 }
 EXPORT_SYMBOL_GPL(nfnl_unlock);
 
+#ifdef CONFIG_PROVE_LOCKING
+int lockdep_nfnl_is_held(u8 subsys_id)
+{
+       return lockdep_is_held(&table[subsys_id].mutex);
+}
+EXPORT_SYMBOL_GPL(lockdep_nfnl_is_held);
+#endif
+
 int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
 {
        nfnl_lock(n->subsys_id);
index a155d19a225edcfb4b1a550ebc898f40d51c564d..d292c8d286ebeac22f688d47df8b793e9c90cc6b 100644 (file)
@@ -28,8 +28,6 @@
 #include <linux/proc_fs.h>
 #include <linux/security.h>
 #include <linux/list.h>
-#include <linux/jhash.h>
-#include <linux/random.h>
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <net/netfilter/nf_log.h>
@@ -75,7 +73,6 @@ struct nfulnl_instance {
 };
 
 #define INSTANCE_BUCKETS       16
-static unsigned int hash_init;
 
 static int nfnl_log_net_id __read_mostly;
 
@@ -1067,11 +1064,6 @@ static int __init nfnetlink_log_init(void)
 {
        int status = -ENOMEM;
 
-       /* it's not really all that important to have a random value, so
-        * we can do this from the init function, even if there hasn't
-        * been that much entropy yet */
-       get_random_bytes(&hash_init, sizeof(hash_init));
-
        netlink_register_notifier(&nfulnl_rtnl_notifier);
        status = nfnetlink_subsys_register(&nfulnl_subsys);
        if (status < 0) {
index 82cb8236f8a101d260a9f3cc6eb1c218e34163f3..8a779be832fba2d8a86181f8f8f68a445299d626 100644 (file)
@@ -192,7 +192,7 @@ err:
 }
 
 static void
-nft_target_destroy(const struct nft_expr *expr)
+nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 {
        struct xt_target *target = expr->ops->data;
 
@@ -379,7 +379,7 @@ err:
 }
 
 static void
-nft_match_destroy(const struct nft_expr *expr)
+nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 {
        struct xt_match *match = expr->ops->data;
 
index 46e2754038387cf978679e2fd4f1032b30e40bd6..bd0d41e693416167b4f149f64117e440a5134496 100644 (file)
 #include <net/netfilter/nf_conntrack_tuple.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_labels.h>
 
 struct nft_ct {
        enum nft_ct_keys        key:8;
        enum ip_conntrack_dir   dir:8;
-       union{
+       union {
                enum nft_registers      dreg:8;
                enum nft_registers      sreg:8;
        };
-       uint8_t                 family;
 };
 
 static void nft_ct_get_eval(const struct nft_expr *expr,
@@ -97,6 +97,26 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
                        goto err;
                strncpy((char *)dest->data, helper->name, sizeof(dest->data));
                return;
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       case NFT_CT_LABELS: {
+               struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+               unsigned int size;
+
+               if (!labels) {
+                       memset(dest->data, 0, sizeof(dest->data));
+                       return;
+               }
+
+               BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > sizeof(dest->data));
+               size = labels->words * sizeof(long);
+
+               memcpy(dest->data, labels->bits, size);
+               if (size < sizeof(dest->data))
+                       memset(((char *) dest->data) + size, 0,
+                              sizeof(dest->data) - size);
+               return;
+       }
+#endif
        }
 
        tuple = &ct->tuplehash[priv->dir].tuple;
@@ -220,6 +240,9 @@ static int nft_ct_init_validate_get(const struct nft_expr *expr,
 #endif
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
        case NFT_CT_SECMARK:
+#endif
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       case NFT_CT_LABELS:
 #endif
        case NFT_CT_EXPIRATION:
        case NFT_CT_HELPER:
@@ -292,16 +315,13 @@ static int nft_ct_init(const struct nft_ctx *ctx,
        if (err < 0)
                return err;
 
-       priv->family = ctx->afi->family;
-
        return 0;
 }
 
-static void nft_ct_destroy(const struct nft_expr *expr)
+static void nft_ct_destroy(const struct nft_ctx *ctx,
+                          const struct nft_expr *expr)
 {
-       struct nft_ct *priv = nft_expr_priv(expr);
-
-       nft_ct_l3proto_module_put(priv->family);
+       nft_ct_l3proto_module_put(ctx->afi->family);
 }
 
 static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
index 3d3f8fce10a5136391e53bd75b13498a45e82e96..6a1acde16c607547f547cc493a2ac7a7f5feb022 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2014 Patrick McHardy <kaber@trash.net>
  *
  * 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
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables.h>
 
+#define NFT_HASH_MIN_SIZE      4
+
 struct nft_hash {
-       struct hlist_head       *hash;
-       unsigned int            hsize;
+       struct nft_hash_table __rcu     *tbl;
+};
+
+struct nft_hash_table {
+       unsigned int                    size;
+       unsigned int                    elements;
+       struct nft_hash_elem __rcu      *buckets[];
 };
 
 struct nft_hash_elem {
-       struct hlist_node       hnode;
-       struct nft_data         key;
-       struct nft_data         data[];
+       struct nft_hash_elem __rcu      *next;
+       struct nft_data                 key;
+       struct nft_data                 data[];
 };
 
+#define nft_hash_for_each_entry(i, head) \
+       for (i = nft_dereference(head); i != NULL; i = nft_dereference(i->next))
+#define nft_hash_for_each_entry_rcu(i, head) \
+       for (i = rcu_dereference(head); i != NULL; i = rcu_dereference(i->next))
+
 static u32 nft_hash_rnd __read_mostly;
 static bool nft_hash_rnd_initted __read_mostly;
 
@@ -38,7 +50,7 @@ static unsigned int nft_hash_data(const struct nft_data *data,
        unsigned int h;
 
        h = jhash(data->data, len, nft_hash_rnd);
-       return ((u64)h * hsize) >> 32;
+       return h & (hsize - 1);
 }
 
 static bool nft_hash_lookup(const struct nft_set *set,
@@ -46,11 +58,12 @@ static bool nft_hash_lookup(const struct nft_set *set,
                            struct nft_data *data)
 {
        const struct nft_hash *priv = nft_set_priv(set);
+       const struct nft_hash_table *tbl = rcu_dereference(priv->tbl);
        const struct nft_hash_elem *he;
        unsigned int h;
 
-       h = nft_hash_data(key, priv->hsize, set->klen);
-       hlist_for_each_entry(he, &priv->hash[h], hnode) {
+       h = nft_hash_data(key, tbl->size, set->klen);
+       nft_hash_for_each_entry_rcu(he, tbl->buckets[h]) {
                if (nft_data_cmp(&he->key, key, set->klen))
                        continue;
                if (set->flags & NFT_SET_MAP)
@@ -60,19 +73,148 @@ static bool nft_hash_lookup(const struct nft_set *set,
        return false;
 }
 
-static void nft_hash_elem_destroy(const struct nft_set *set,
-                                 struct nft_hash_elem *he)
+static void nft_hash_tbl_free(const struct nft_hash_table *tbl)
 {
-       nft_data_uninit(&he->key, NFT_DATA_VALUE);
-       if (set->flags & NFT_SET_MAP)
-               nft_data_uninit(he->data, set->dtype);
-       kfree(he);
+       if (is_vmalloc_addr(tbl))
+               vfree(tbl);
+       else
+               kfree(tbl);
+}
+
+static struct nft_hash_table *nft_hash_tbl_alloc(unsigned int nbuckets)
+{
+       struct nft_hash_table *tbl;
+       size_t size;
+
+       size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]);
+       tbl = kzalloc(size, GFP_KERNEL | __GFP_REPEAT | __GFP_NOWARN);
+       if (tbl == NULL)
+               tbl = vzalloc(size);
+       if (tbl == NULL)
+               return NULL;
+       tbl->size = nbuckets;
+
+       return tbl;
+}
+
+static void nft_hash_chain_unzip(const struct nft_set *set,
+                                const struct nft_hash_table *ntbl,
+                                struct nft_hash_table *tbl, unsigned int n)
+{
+       struct nft_hash_elem *he, *last, *next;
+       unsigned int h;
+
+       he = nft_dereference(tbl->buckets[n]);
+       if (he == NULL)
+               return;
+       h = nft_hash_data(&he->key, ntbl->size, set->klen);
+
+       /* Find last element of first chain hashing to bucket h */
+       last = he;
+       nft_hash_for_each_entry(he, he->next) {
+               if (nft_hash_data(&he->key, ntbl->size, set->klen) != h)
+                       break;
+               last = he;
+       }
+
+       /* Unlink first chain from the old table */
+       RCU_INIT_POINTER(tbl->buckets[n], last->next);
+
+       /* If end of chain reached, done */
+       if (he == NULL)
+               return;
+
+       /* Find first element of second chain hashing to bucket h */
+       next = NULL;
+       nft_hash_for_each_entry(he, he->next) {
+               if (nft_hash_data(&he->key, ntbl->size, set->klen) != h)
+                       continue;
+               next = he;
+               break;
+       }
+
+       /* Link the two chains */
+       RCU_INIT_POINTER(last->next, next);
+}
+
+static int nft_hash_tbl_expand(const struct nft_set *set, struct nft_hash *priv)
+{
+       struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl;
+       struct nft_hash_elem *he;
+       unsigned int i, h;
+       bool complete;
+
+       ntbl = nft_hash_tbl_alloc(tbl->size * 2);
+       if (ntbl == NULL)
+               return -ENOMEM;
+
+       /* Link new table's buckets to first element in the old table
+        * hashing to the new bucket.
+        */
+       for (i = 0; i < ntbl->size; i++) {
+               h = i < tbl->size ? i : i - tbl->size;
+               nft_hash_for_each_entry(he, tbl->buckets[h]) {
+                       if (nft_hash_data(&he->key, ntbl->size, set->klen) != i)
+                               continue;
+                       RCU_INIT_POINTER(ntbl->buckets[i], he);
+                       break;
+               }
+       }
+       ntbl->elements = tbl->elements;
+
+       /* Publish new table */
+       rcu_assign_pointer(priv->tbl, ntbl);
+
+       /* Unzip interleaved hash chains */
+       do {
+               /* Wait for readers to use new table/unzipped chains */
+               synchronize_rcu();
+
+               complete = true;
+               for (i = 0; i < tbl->size; i++) {
+                       nft_hash_chain_unzip(set, ntbl, tbl, i);
+                       if (tbl->buckets[i] != NULL)
+                               complete = false;
+               }
+       } while (!complete);
+
+       nft_hash_tbl_free(tbl);
+       return 0;
+}
+
+static int nft_hash_tbl_shrink(const struct nft_set *set, struct nft_hash *priv)
+{
+       struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl;
+       struct nft_hash_elem __rcu **pprev;
+       unsigned int i;
+
+       ntbl = nft_hash_tbl_alloc(tbl->size / 2);
+       if (ntbl == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < ntbl->size; i++) {
+               ntbl->buckets[i] = tbl->buckets[i];
+
+               for (pprev = &ntbl->buckets[i]; *pprev != NULL;
+                    pprev = &nft_dereference(*pprev)->next)
+                       ;
+               RCU_INIT_POINTER(*pprev, tbl->buckets[i + ntbl->size]);
+       }
+       ntbl->elements = tbl->elements;
+
+       /* Publish new table */
+       rcu_assign_pointer(priv->tbl, ntbl);
+       synchronize_rcu();
+
+       nft_hash_tbl_free(tbl);
+       return 0;
 }
 
 static int nft_hash_insert(const struct nft_set *set,
                           const struct nft_set_elem *elem)
 {
        struct nft_hash *priv = nft_set_priv(set);
+       struct nft_hash_table *tbl = nft_dereference(priv->tbl);
        struct nft_hash_elem *he;
        unsigned int size, h;
 
@@ -91,33 +233,66 @@ static int nft_hash_insert(const struct nft_set *set,
        if (set->flags & NFT_SET_MAP)
                nft_data_copy(he->data, &elem->data);
 
-       h = nft_hash_data(&he->key, priv->hsize, set->klen);
-       hlist_add_head_rcu(&he->hnode, &priv->hash[h]);
+       h = nft_hash_data(&he->key, tbl->size, set->klen);
+       RCU_INIT_POINTER(he->next, tbl->buckets[h]);
+       rcu_assign_pointer(tbl->buckets[h], he);
+       tbl->elements++;
+
+       /* Expand table when exceeding 75% load */
+       if (tbl->elements > tbl->size / 4 * 3)
+               nft_hash_tbl_expand(set, priv);
+
        return 0;
 }
 
+static void nft_hash_elem_destroy(const struct nft_set *set,
+                                 struct nft_hash_elem *he)
+{
+       nft_data_uninit(&he->key, NFT_DATA_VALUE);
+       if (set->flags & NFT_SET_MAP)
+               nft_data_uninit(he->data, set->dtype);
+       kfree(he);
+}
+
 static void nft_hash_remove(const struct nft_set *set,
                            const struct nft_set_elem *elem)
 {
-       struct nft_hash_elem *he = elem->cookie;
+       struct nft_hash *priv = nft_set_priv(set);
+       struct nft_hash_table *tbl = nft_dereference(priv->tbl);
+       struct nft_hash_elem *he, __rcu **pprev;
 
-       hlist_del_rcu(&he->hnode);
+       pprev = elem->cookie;
+       he = nft_dereference((*pprev));
+
+       RCU_INIT_POINTER(*pprev, he->next);
+       synchronize_rcu();
        kfree(he);
+       tbl->elements--;
+
+       /* Shrink table beneath 30% load */
+       if (tbl->elements < tbl->size * 3 / 10 &&
+           tbl->size > NFT_HASH_MIN_SIZE)
+               nft_hash_tbl_shrink(set, priv);
 }
 
 static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem)
 {
        const struct nft_hash *priv = nft_set_priv(set);
+       const struct nft_hash_table *tbl = nft_dereference(priv->tbl);
+       struct nft_hash_elem __rcu * const *pprev;
        struct nft_hash_elem *he;
        unsigned int h;
 
-       h = nft_hash_data(&elem->key, priv->hsize, set->klen);
-       hlist_for_each_entry(he, &priv->hash[h], hnode) {
-               if (nft_data_cmp(&he->key, &elem->key, set->klen))
+       h = nft_hash_data(&elem->key, tbl->size, set->klen);
+       pprev = &tbl->buckets[h];
+       nft_hash_for_each_entry(he, tbl->buckets[h]) {
+               if (nft_data_cmp(&he->key, &elem->key, set->klen)) {
+                       pprev = &he->next;
                        continue;
+               }
 
-               elem->cookie = he;
-               elem->flags  = 0;
+               elem->cookie = (void *)pprev;
+               elem->flags = 0;
                if (set->flags & NFT_SET_MAP)
                        nft_data_copy(&elem->data, he->data);
                return 0;
@@ -129,12 +304,13 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
                          struct nft_set_iter *iter)
 {
        const struct nft_hash *priv = nft_set_priv(set);
+       const struct nft_hash_table *tbl = nft_dereference(priv->tbl);
        const struct nft_hash_elem *he;
        struct nft_set_elem elem;
        unsigned int i;
 
-       for (i = 0; i < priv->hsize; i++) {
-               hlist_for_each_entry(he, &priv->hash[i], hnode) {
+       for (i = 0; i < tbl->size; i++) {
+               nft_hash_for_each_entry(he, tbl->buckets[i]) {
                        if (iter->count < iter->skip)
                                goto cont;
 
@@ -161,43 +337,35 @@ static int nft_hash_init(const struct nft_set *set,
                         const struct nlattr * const tb[])
 {
        struct nft_hash *priv = nft_set_priv(set);
-       unsigned int cnt, i;
+       struct nft_hash_table *tbl;
 
        if (unlikely(!nft_hash_rnd_initted)) {
                get_random_bytes(&nft_hash_rnd, 4);
                nft_hash_rnd_initted = true;
        }
 
-       /* Aim for a load factor of 0.75 */
-       // FIXME: temporarily broken until we have set descriptions
-       cnt = 100;
-       cnt = cnt * 4 / 3;
-
-       priv->hash = kcalloc(cnt, sizeof(struct hlist_head), GFP_KERNEL);
-       if (priv->hash == NULL)
+       tbl = nft_hash_tbl_alloc(NFT_HASH_MIN_SIZE);
+       if (tbl == NULL)
                return -ENOMEM;
-       priv->hsize = cnt;
-
-       for (i = 0; i < cnt; i++)
-               INIT_HLIST_HEAD(&priv->hash[i]);
-
+       RCU_INIT_POINTER(priv->tbl, tbl);
        return 0;
 }
 
 static void nft_hash_destroy(const struct nft_set *set)
 {
        const struct nft_hash *priv = nft_set_priv(set);
-       const struct hlist_node *next;
-       struct nft_hash_elem *elem;
+       const struct nft_hash_table *tbl = nft_dereference(priv->tbl);
+       struct nft_hash_elem *he, *next;
        unsigned int i;
 
-       for (i = 0; i < priv->hsize; i++) {
-               hlist_for_each_entry_safe(elem, next, &priv->hash[i], hnode) {
-                       hlist_del(&elem->hnode);
-                       nft_hash_elem_destroy(set, elem);
+       for (i = 0; i < tbl->size; i++) {
+               for (he = nft_dereference(tbl->buckets[i]); he != NULL;
+                    he = next) {
+                       next = nft_dereference(he->next);
+                       nft_hash_elem_destroy(set, he);
                }
        }
-       kfree(priv->hash);
+       kfree(tbl);
 }
 
 static struct nft_set_ops nft_hash_ops __read_mostly = {
index f169501f1ad4389970613d1e44fb2b60759406cb..810385eb7249c7be39bcbc0e6c34abc1a6b1708d 100644 (file)
@@ -70,7 +70,8 @@ err1:
        return err;
 }
 
-static void nft_immediate_destroy(const struct nft_expr *expr)
+static void nft_immediate_destroy(const struct nft_ctx *ctx,
+                                 const struct nft_expr *expr)
 {
        const struct nft_immediate_expr *priv = nft_expr_priv(expr);
        return nft_data_uninit(&priv->data, nft_dreg_to_type(priv->dreg));
index 26c5154e05f3fc09aae2ebdea968ce564a3d5eb9..10cfb156cdf4449dee49e53667549e5c2fccdf82 100644 (file)
@@ -74,7 +74,8 @@ static int nft_log_init(const struct nft_ctx *ctx,
        return 0;
 }
 
-static void nft_log_destroy(const struct nft_expr *expr)
+static void nft_log_destroy(const struct nft_ctx *ctx,
+                           const struct nft_expr *expr)
 {
        struct nft_log *priv = nft_expr_priv(expr);
 
index bb4ef4cccb6efcdf937bc3417eb8dbd6ccf0e22f..7fd2bea8aa239f347dc461c7bc45869dac405573 100644 (file)
@@ -89,11 +89,12 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
        return 0;
 }
 
-static void nft_lookup_destroy(const struct nft_expr *expr)
+static void nft_lookup_destroy(const struct nft_ctx *ctx,
+                              const struct nft_expr *expr)
 {
        struct nft_lookup *priv = nft_expr_priv(expr);
 
-       nf_tables_unbind_set(NULL, priv->set, &priv->binding);
+       nf_tables_unbind_set(ctx, priv->set, &priv->binding);
 }
 
 static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
index e8254ad2e5a9f37e84694293c8ba4069b5e5f35e..425cf39af8907f1d0618b0904121073ea4dc116a 100644 (file)
@@ -116,7 +116,7 @@ static void nft_meta_get_eval(const struct nft_expr *expr,
                                 skb->sk->sk_socket->file->f_cred->fsgid);
                read_unlock_bh(&skb->sk->sk_callback_lock);
                break;
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
        case NFT_META_RTCLASSID: {
                const struct dst_entry *dst = skb_dst(skb);
 
@@ -199,7 +199,7 @@ static int nft_meta_init_validate_get(uint32_t key)
        case NFT_META_OIFTYPE:
        case NFT_META_SKUID:
        case NFT_META_SKGID:
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
        case NFT_META_RTCLASSID:
 #endif
 #ifdef CONFIG_NETWORK_SECMARK
index d3b1ffe26181b22538ab29fefadd7a41d96b76f1..a0195d28bcfc2e5b90025ac9ceb14499d1747934 100644 (file)
@@ -31,8 +31,8 @@ struct nft_nat {
        enum nft_registers      sreg_addr_max:8;
        enum nft_registers      sreg_proto_min:8;
        enum nft_registers      sreg_proto_max:8;
-       int                     family;
-       enum nf_nat_manip_type  type;
+       enum nf_nat_manip_type  type:8;
+       u8                      family;
 };
 
 static void nft_nat_eval(const struct nft_expr *expr,
@@ -88,6 +88,7 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                        const struct nlattr * const tb[])
 {
        struct nft_nat *priv = nft_expr_priv(expr);
+       u32 family;
        int err;
 
        if (tb[NFTA_NAT_TYPE] == NULL)
@@ -107,9 +108,12 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        if (tb[NFTA_NAT_FAMILY] == NULL)
                return -EINVAL;
 
-       priv->family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
-       if (priv->family != AF_INET && priv->family != AF_INET6)
-               return -EINVAL;
+       family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
+       if (family != AF_INET && family != AF_INET6)
+               return -EAFNOSUPPORT;
+       if (family != ctx->afi->family)
+               return -EOPNOTSUPP;
+       priv->family = family;
 
        if (tb[NFTA_NAT_REG_ADDR_MIN]) {
                priv->sreg_addr_min = ntohl(nla_get_be32(
@@ -202,13 +206,7 @@ static struct nft_expr_type nft_nat_type __read_mostly = {
 
 static int __init nft_nat_module_init(void)
 {
-       int err;
-
-       err = nft_register_expr(&nft_nat_type);
-       if (err < 0)
-               return err;
-
-       return 0;
+       return nft_register_expr(&nft_nat_type);
 }
 
 static void __exit nft_nat_module_exit(void)
index a2aeb318678f9e0e577801f6e42bda4df66ea805..85daa84bfdfee3d65296fb62c723a78e180c4497 100644 (file)
@@ -135,7 +135,8 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
        if (len == 0 || len > FIELD_SIZEOF(struct nft_data, data))
                return ERR_PTR(-EINVAL);
 
-       if (len <= 4 && IS_ALIGNED(offset, len) && base != NFT_PAYLOAD_LL_HEADER)
+       if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
+           base != NFT_PAYLOAD_LL_HEADER)
                return &nft_payload_fast_ops;
        else
                return &nft_payload_ops;
index 8a310f239c93ed769f0eeadc1ce30c97fcd63de8..b718a52a46544036ba81a4105da149d8261d30c3 100644 (file)
@@ -21,9 +21,9 @@ static void nft_reject_inet_eval(const struct nft_expr *expr,
 {
        switch (pkt->ops->pf) {
        case NFPROTO_IPV4:
-               nft_reject_ipv4_eval(expr, data, pkt);
+               return nft_reject_ipv4_eval(expr, data, pkt);
        case NFPROTO_IPV6:
-               nft_reject_ipv6_eval(expr, data, pkt);
+               return nft_reject_ipv6_eval(expr, data, pkt);
        }
 }
 
index 3228d7f24eb4107ff717af4323e834af3e680797..4973cbddc446bd50a377765bec23128716ff630e 100644 (file)
@@ -146,11 +146,11 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par)
 
                if (par->family == NFPROTO_BRIDGE) {
                        switch (eth_hdr(skb)->h_proto) {
-                       case __constant_htons(ETH_P_IP):
+                       case htons(ETH_P_IP):
                                audit_ip4(ab, skb);
                                break;
 
-                       case __constant_htons(ETH_P_IPV6):
+                       case htons(ETH_P_IPV6):
                                audit_ip6(ab, skb);
                                break;
                        }
index c40b2695633b15960ac65eb84ebc2405b4aa2c1c..458464e7bd7a841915aeebdd448cb17bb49c01e4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/jhash.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/rbtree.h>
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/skbuff.h>
 #include <net/netfilter/nf_conntrack_tuple.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 
+#define CONNLIMIT_SLOTS                32
+#define CONNLIMIT_LOCK_SLOTS   32
+#define CONNLIMIT_GC_MAX_NODES 8
+
 /* we will save the tuples of all connections we care about */
 struct xt_connlimit_conn {
        struct hlist_node               node;
@@ -38,16 +43,26 @@ struct xt_connlimit_conn {
        union nf_inet_addr              addr;
 };
 
+struct xt_connlimit_rb {
+       struct rb_node node;
+       struct hlist_head hhead; /* connections/hosts in same subnet */
+       union nf_inet_addr addr; /* search key */
+};
+
 struct xt_connlimit_data {
-       struct hlist_head       iphash[256];
-       spinlock_t              lock;
+       struct rb_root climit_root4[CONNLIMIT_SLOTS];
+       struct rb_root climit_root6[CONNLIMIT_SLOTS];
+       spinlock_t              locks[CONNLIMIT_LOCK_SLOTS];
 };
 
 static u_int32_t connlimit_rnd __read_mostly;
+static struct kmem_cache *connlimit_rb_cachep __read_mostly;
+static struct kmem_cache *connlimit_conn_cachep __read_mostly;
 
 static inline unsigned int connlimit_iphash(__be32 addr)
 {
-       return jhash_1word((__force __u32)addr, connlimit_rnd) & 0xFF;
+       return jhash_1word((__force __u32)addr,
+                           connlimit_rnd) % CONNLIMIT_SLOTS;
 }
 
 static inline unsigned int
@@ -60,7 +75,8 @@ connlimit_iphash6(const union nf_inet_addr *addr,
        for (i = 0; i < ARRAY_SIZE(addr->ip6); ++i)
                res.ip6[i] = addr->ip6[i] & mask->ip6[i];
 
-       return jhash2((u32 *)res.ip6, ARRAY_SIZE(res.ip6), connlimit_rnd) & 0xFF;
+       return jhash2((u32 *)res.ip6, ARRAY_SIZE(res.ip6),
+                      connlimit_rnd) % CONNLIMIT_SLOTS;
 }
 
 static inline bool already_closed(const struct nf_conn *conn)
@@ -72,13 +88,14 @@ static inline bool already_closed(const struct nf_conn *conn)
                return 0;
 }
 
-static inline unsigned int
+static int
 same_source_net(const union nf_inet_addr *addr,
                const union nf_inet_addr *mask,
                const union nf_inet_addr *u3, u_int8_t family)
 {
        if (family == NFPROTO_IPV4) {
-               return (addr->ip & mask->ip) == (u3->ip & mask->ip);
+               return ntohl(addr->ip & mask->ip) -
+                      ntohl(u3->ip & mask->ip);
        } else {
                union nf_inet_addr lh, rh;
                unsigned int i;
@@ -88,89 +105,205 @@ same_source_net(const union nf_inet_addr *addr,
                        rh.ip6[i] = u3->ip6[i] & mask->ip6[i];
                }
 
-               return memcmp(&lh.ip6, &rh.ip6, sizeof(lh.ip6)) == 0;
+               return memcmp(&lh.ip6, &rh.ip6, sizeof(lh.ip6));
        }
 }
 
-static int count_them(struct net *net,
-                     struct xt_connlimit_data *data,
+static bool add_hlist(struct hlist_head *head,
                      const struct nf_conntrack_tuple *tuple,
-                     const union nf_inet_addr *addr,
-                     const union nf_inet_addr *mask,
-                     u_int8_t family)
+                     const union nf_inet_addr *addr)
+{
+       struct xt_connlimit_conn *conn;
+
+       conn = kmem_cache_alloc(connlimit_conn_cachep, GFP_ATOMIC);
+       if (conn == NULL)
+               return false;
+       conn->tuple = *tuple;
+       conn->addr = *addr;
+       hlist_add_head(&conn->node, head);
+       return true;
+}
+
+static unsigned int check_hlist(struct net *net,
+                               struct hlist_head *head,
+                               const struct nf_conntrack_tuple *tuple,
+                               bool *addit)
 {
        const struct nf_conntrack_tuple_hash *found;
        struct xt_connlimit_conn *conn;
        struct hlist_node *n;
        struct nf_conn *found_ct;
-       struct hlist_head *hash;
-       bool addit = true;
-       int matches = 0;
-
-       if (family == NFPROTO_IPV6)
-               hash = &data->iphash[connlimit_iphash6(addr, mask)];
-       else
-               hash = &data->iphash[connlimit_iphash(addr->ip & mask->ip)];
+       unsigned int length = 0;
 
+       *addit = true;
        rcu_read_lock();
 
        /* check the saved connections */
-       hlist_for_each_entry_safe(conn, n, hash, node) {
+       hlist_for_each_entry_safe(conn, n, head, node) {
                found    = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE,
                                                 &conn->tuple);
-               found_ct = NULL;
+               if (found == NULL) {
+                       hlist_del(&conn->node);
+                       kmem_cache_free(connlimit_conn_cachep, conn);
+                       continue;
+               }
 
-               if (found != NULL)
-                       found_ct = nf_ct_tuplehash_to_ctrack(found);
+               found_ct = nf_ct_tuplehash_to_ctrack(found);
 
-               if (found_ct != NULL &&
-                   nf_ct_tuple_equal(&conn->tuple, tuple) &&
-                   !already_closed(found_ct))
+               if (nf_ct_tuple_equal(&conn->tuple, tuple)) {
                        /*
                         * Just to be sure we have it only once in the list.
                         * We should not see tuples twice unless someone hooks
                         * this into a table without "-p tcp --syn".
                         */
-                       addit = false;
-
-               if (found == NULL) {
-                       /* this one is gone */
-                       hlist_del(&conn->node);
-                       kfree(conn);
-                       continue;
-               }
-
-               if (already_closed(found_ct)) {
+                       *addit = false;
+               } else if (already_closed(found_ct)) {
                        /*
                         * we do not care about connections which are
                         * closed already -> ditch it
                         */
                        nf_ct_put(found_ct);
                        hlist_del(&conn->node);
-                       kfree(conn);
+                       kmem_cache_free(connlimit_conn_cachep, conn);
                        continue;
                }
 
-               if (same_source_net(addr, mask, &conn->addr, family))
-                       /* same source network -> be counted! */
-                       ++matches;
                nf_ct_put(found_ct);
+               length++;
        }
 
        rcu_read_unlock();
 
-       if (addit) {
-               /* save the new connection in our list */
-               conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
-               if (conn == NULL)
-                       return -ENOMEM;
-               conn->tuple = *tuple;
-               conn->addr = *addr;
-               hlist_add_head(&conn->node, hash);
-               ++matches;
+       return length;
+}
+
+static void tree_nodes_free(struct rb_root *root,
+                           struct xt_connlimit_rb *gc_nodes[],
+                           unsigned int gc_count)
+{
+       struct xt_connlimit_rb *rbconn;
+
+       while (gc_count) {
+               rbconn = gc_nodes[--gc_count];
+               rb_erase(&rbconn->node, root);
+               kmem_cache_free(connlimit_rb_cachep, rbconn);
+       }
+}
+
+static unsigned int
+count_tree(struct net *net, struct rb_root *root,
+          const struct nf_conntrack_tuple *tuple,
+          const union nf_inet_addr *addr, const union nf_inet_addr *mask,
+          u8 family)
+{
+       struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES];
+       struct rb_node **rbnode, *parent;
+       struct xt_connlimit_rb *rbconn;
+       struct xt_connlimit_conn *conn;
+       unsigned int gc_count;
+       bool no_gc = false;
+
+ restart:
+       gc_count = 0;
+       parent = NULL;
+       rbnode = &(root->rb_node);
+       while (*rbnode) {
+               int diff;
+               bool addit;
+
+               rbconn = container_of(*rbnode, struct xt_connlimit_rb, node);
+
+               parent = *rbnode;
+               diff = same_source_net(addr, mask, &rbconn->addr, family);
+               if (diff < 0) {
+                       rbnode = &((*rbnode)->rb_left);
+               } else if (diff > 0) {
+                       rbnode = &((*rbnode)->rb_right);
+               } else {
+                       /* same source network -> be counted! */
+                       unsigned int count;
+                       count = check_hlist(net, &rbconn->hhead, tuple, &addit);
+
+                       tree_nodes_free(root, gc_nodes, gc_count);
+                       if (!addit)
+                               return count;
+
+                       if (!add_hlist(&rbconn->hhead, tuple, addr))
+                               return 0; /* hotdrop */
+
+                       return count + 1;
+               }
+
+               if (no_gc || gc_count >= ARRAY_SIZE(gc_nodes))
+                       continue;
+
+               /* only used for GC on hhead, retval and 'addit' ignored */
+               check_hlist(net, &rbconn->hhead, tuple, &addit);
+               if (hlist_empty(&rbconn->hhead))
+                       gc_nodes[gc_count++] = rbconn;
+       }
+
+       if (gc_count) {
+               no_gc = true;
+               tree_nodes_free(root, gc_nodes, gc_count);
+               /* tree_node_free before new allocation permits
+                * allocator to re-use newly free'd object.
+                *
+                * This is a rare event; in most cases we will find
+                * existing node to re-use. (or gc_count is 0).
+                */
+               goto restart;
+       }
+
+       /* no match, need to insert new node */
+       rbconn = kmem_cache_alloc(connlimit_rb_cachep, GFP_ATOMIC);
+       if (rbconn == NULL)
+               return 0;
+
+       conn = kmem_cache_alloc(connlimit_conn_cachep, GFP_ATOMIC);
+       if (conn == NULL) {
+               kmem_cache_free(connlimit_rb_cachep, rbconn);
+               return 0;
+       }
+
+       conn->tuple = *tuple;
+       conn->addr = *addr;
+       rbconn->addr = *addr;
+
+       INIT_HLIST_HEAD(&rbconn->hhead);
+       hlist_add_head(&conn->node, &rbconn->hhead);
+
+       rb_link_node(&rbconn->node, parent, rbnode);
+       rb_insert_color(&rbconn->node, root);
+       return 1;
+}
+
+static int count_them(struct net *net,
+                     struct xt_connlimit_data *data,
+                     const struct nf_conntrack_tuple *tuple,
+                     const union nf_inet_addr *addr,
+                     const union nf_inet_addr *mask,
+                     u_int8_t family)
+{
+       struct rb_root *root;
+       int count;
+       u32 hash;
+
+       if (family == NFPROTO_IPV6) {
+               hash = connlimit_iphash6(addr, mask);
+               root = &data->climit_root6[hash];
+       } else {
+               hash = connlimit_iphash(addr->ip & mask->ip);
+               root = &data->climit_root4[hash];
        }
 
-       return matches;
+       spin_lock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]);
+
+       count = count_tree(net, root, tuple, addr, mask, family);
+
+       spin_unlock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]);
+
+       return count;
 }
 
 static bool
@@ -183,7 +316,7 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
        const struct nf_conntrack_tuple *tuple_ptr = &tuple;
        enum ip_conntrack_info ctinfo;
        const struct nf_conn *ct;
-       int connections;
+       unsigned int connections;
 
        ct = nf_ct_get(skb, &ctinfo);
        if (ct != NULL)
@@ -202,12 +335,9 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
                          iph->daddr : iph->saddr;
        }
 
-       spin_lock_bh(&info->data->lock);
        connections = count_them(net, info->data, tuple_ptr, &addr,
                                 &info->mask, par->family);
-       spin_unlock_bh(&info->data->lock);
-
-       if (connections < 0)
+       if (connections == 0)
                /* kmalloc failed, drop it entirely */
                goto hotdrop;
 
@@ -247,29 +377,47 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par)
                return -ENOMEM;
        }
 
-       spin_lock_init(&info->data->lock);
-       for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i)
-               INIT_HLIST_HEAD(&info->data->iphash[i]);
+       for (i = 0; i < ARRAY_SIZE(info->data->locks); ++i)
+               spin_lock_init(&info->data->locks[i]);
+
+       for (i = 0; i < ARRAY_SIZE(info->data->climit_root4); ++i)
+               info->data->climit_root4[i] = RB_ROOT;
+       for (i = 0; i < ARRAY_SIZE(info->data->climit_root6); ++i)
+               info->data->climit_root6[i] = RB_ROOT;
 
        return 0;
 }
 
-static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
+static void destroy_tree(struct rb_root *r)
 {
-       const struct xt_connlimit_info *info = par->matchinfo;
        struct xt_connlimit_conn *conn;
+       struct xt_connlimit_rb *rbconn;
        struct hlist_node *n;
-       struct hlist_head *hash = info->data->iphash;
+       struct rb_node *node;
+
+       while ((node = rb_first(r)) != NULL) {
+               rbconn = container_of(node, struct xt_connlimit_rb, node);
+
+               rb_erase(node, r);
+
+               hlist_for_each_entry_safe(conn, n, &rbconn->hhead, node)
+                       kmem_cache_free(connlimit_conn_cachep, conn);
+
+               kmem_cache_free(connlimit_rb_cachep, rbconn);
+       }
+}
+
+static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
+{
+       const struct xt_connlimit_info *info = par->matchinfo;
        unsigned int i;
 
        nf_ct_l3proto_module_put(par->family);
 
-       for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) {
-               hlist_for_each_entry_safe(conn, n, &hash[i], node) {
-                       hlist_del(&conn->node);
-                       kfree(conn);
-               }
-       }
+       for (i = 0; i < ARRAY_SIZE(info->data->climit_root4); ++i)
+               destroy_tree(&info->data->climit_root4[i]);
+       for (i = 0; i < ARRAY_SIZE(info->data->climit_root6); ++i)
+               destroy_tree(&info->data->climit_root6[i]);
 
        kfree(info->data);
 }
@@ -287,12 +435,37 @@ static struct xt_match connlimit_mt_reg __read_mostly = {
 
 static int __init connlimit_mt_init(void)
 {
-       return xt_register_match(&connlimit_mt_reg);
+       int ret;
+
+       BUILD_BUG_ON(CONNLIMIT_LOCK_SLOTS > CONNLIMIT_SLOTS);
+       BUILD_BUG_ON((CONNLIMIT_SLOTS % CONNLIMIT_LOCK_SLOTS) != 0);
+
+       connlimit_conn_cachep = kmem_cache_create("xt_connlimit_conn",
+                                          sizeof(struct xt_connlimit_conn),
+                                          0, 0, NULL);
+       if (!connlimit_conn_cachep)
+               return -ENOMEM;
+
+       connlimit_rb_cachep = kmem_cache_create("xt_connlimit_rb",
+                                          sizeof(struct xt_connlimit_rb),
+                                          0, 0, NULL);
+       if (!connlimit_rb_cachep) {
+               kmem_cache_destroy(connlimit_conn_cachep);
+               return -ENOMEM;
+       }
+       ret = xt_register_match(&connlimit_mt_reg);
+       if (ret != 0) {
+               kmem_cache_destroy(connlimit_conn_cachep);
+               kmem_cache_destroy(connlimit_rb_cachep);
+       }
+       return ret;
 }
 
 static void __exit connlimit_mt_exit(void)
 {
        xt_unregister_match(&connlimit_mt_reg);
+       kmem_cache_destroy(connlimit_conn_cachep);
+       kmem_cache_destroy(connlimit_rb_cachep);
 }
 
 module_init(connlimit_mt_init);
index a4c7561698c5c2fa5dd9b79717e0cc7116347e54..89d53104c6b365b12c76ff684064bc5d032656c3 100644 (file)
@@ -60,7 +60,7 @@ static bool comp_mt(const struct sk_buff *skb, struct xt_action_param *par)
        }
 
        return spi_match(compinfo->spis[0], compinfo->spis[1],
-                        ntohl(chdr->cpi << 16),
+                        ntohs(chdr->cpi),
                         !!(compinfo->invflags & XT_IPCOMP_INV_SPI));
 }
 
index e42214b932c379f0ce4ffd422b10387c10d6dd52..c2d585c4f7c5cb2c82ea2adb03723e90b61c91f1 100644 (file)
@@ -1489,8 +1489,8 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
        if (addr->sa_family != AF_NETLINK)
                return -EINVAL;
 
-       /* Only superuser is allowed to send multicasts */
-       if (nladdr->nl_groups && !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
+       if ((nladdr->nl_groups || nladdr->nl_pid) &&
+           !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
                return -EPERM;
 
        if (!nlk->portid)
@@ -2343,6 +2343,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
        }
 #endif
 
+       /* Record the max length of recvmsg() calls for future allocations */
+       nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len);
+       nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len,
+                                    16384);
+
        copied = data_skb->len;
        if (len < copied) {
                msg->msg_flags |= MSG_TRUNC;
@@ -2587,7 +2592,27 @@ static int netlink_dump(struct sock *sk)
        if (!netlink_rx_is_mmaped(sk) &&
            atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
                goto errout_skb;
-       skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, GFP_KERNEL);
+
+       /* NLMSG_GOODSIZE is small to avoid high order allocations being
+        * required, but it makes sense to _attempt_ a 16K bytes allocation
+        * to reduce number of system calls on dump operations, if user
+        * ever provided a big enough buffer.
+        */
+       if (alloc_size < nlk->max_recvmsg_len) {
+               skb = netlink_alloc_skb(sk,
+                                       nlk->max_recvmsg_len,
+                                       nlk->portid,
+                                       GFP_KERNEL |
+                                       __GFP_NOWARN |
+                                       __GFP_NORETRY);
+               /* available room should be exact amount to avoid MSG_TRUNC */
+               if (skb)
+                       skb_reserve(skb, skb_tailroom(skb) -
+                                        nlk->max_recvmsg_len);
+       }
+       if (!skb)
+               skb = netlink_alloc_skb(sk, alloc_size, nlk->portid,
+                                       GFP_KERNEL);
        if (!skb)
                goto errout_skb;
        netlink_skb_set_owner_r(skb, sk);
index acbd774eeb7c5afd568d8eb9aa375ecc81949793..ed13a790b00e1684215e04c6a68f71f9491cb3c9 100644 (file)
@@ -31,6 +31,7 @@ struct netlink_sock {
        u32                     ngroups;
        unsigned long           *groups;
        unsigned long           state;
+       size_t                  max_recvmsg_len;
        wait_queue_head_t       wait;
        bool                    cb_running;
        struct netlink_callback cb;
index 46bda010bf11740c1a2fcd9002a193a7ab70801a..56db888b1cd56785e23f0e0272d4ae3af87e32e6 100644 (file)
@@ -301,7 +301,7 @@ static int nci_open_device(struct nci_dev *ndev)
        rc = __nci_request(ndev, nci_reset_req, 0,
                           msecs_to_jiffies(NCI_RESET_TIMEOUT));
 
-       if (ndev->ops->setup(ndev))
+       if (ndev->ops->setup)
                ndev->ops->setup(ndev);
 
        if (!rc) {
index 36f8872cb07284031391eebe253fca6a5fac5fac..c53fe0c9697cfa6932ae292a10495c430861b30d 100644 (file)
@@ -606,9 +606,9 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats,
                percpu_stats = per_cpu_ptr(dp->stats_percpu, i);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&percpu_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&percpu_stats->syncp);
                        local_stats = *percpu_stats;
-               } while (u64_stats_fetch_retry_bh(&percpu_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start));
 
                stats->n_hit += local_stats.n_hit;
                stats->n_missed += local_stats.n_missed;
index 3b4db322045644ccfcf33cf93b556e4bc10869a3..42c0f4a0b78c4c3033ab77d12c376590c228459d 100644 (file)
@@ -277,9 +277,9 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats)
                percpu_stats = per_cpu_ptr(vport->percpu_stats, i);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&percpu_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&percpu_stats->syncp);
                        local_stats = *percpu_stats;
-               } while (u64_stats_fetch_retry_bh(&percpu_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start));
 
                stats->rx_bytes         += local_stats.rx_bytes;
                stats->rx_packets       += local_stats.rx_packets;
index d1c3429b69eddd49face1e8cc4967ad8afa07c7c..ec126f91276b349c7fe8e181ad4ce7aec24f0c67 100644 (file)
@@ -20,9 +20,8 @@ af-rxrpc-y := \
        ar-skbuff.o \
        ar-transport.o
 
-ifeq ($(CONFIG_PROC_FS),y)
-af-rxrpc-y += ar-proc.o
-endif
+af-rxrpc-$(CONFIG_PROC_FS) += ar-proc.o
+af-rxrpc-$(CONFIG_SYSCTL) += sysctl.o
 
 obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o
 
index e61aa6001c65fb5c7521b02cb693a409f62fe1fe..7b1670489638e565c7ccea71961f8532986c94cb 100644 (file)
@@ -838,6 +838,12 @@ static int __init af_rxrpc_init(void)
                goto error_key_type_s;
        }
 
+       ret = rxrpc_sysctl_init();
+       if (ret < 0) {
+               printk(KERN_CRIT "RxRPC: Cannot register sysctls\n");
+               goto error_sysctls;
+       }
+
 #ifdef CONFIG_PROC_FS
        proc_create("rxrpc_calls", 0, init_net.proc_net, &rxrpc_call_seq_fops);
        proc_create("rxrpc_conns", 0, init_net.proc_net,
@@ -845,6 +851,8 @@ static int __init af_rxrpc_init(void)
 #endif
        return 0;
 
+error_sysctls:
+       unregister_key_type(&key_type_rxrpc_s);
 error_key_type_s:
        unregister_key_type(&key_type_rxrpc);
 error_key_type:
@@ -865,6 +873,7 @@ error_call_jar:
 static void __exit af_rxrpc_exit(void)
 {
        _enter("");
+       rxrpc_sysctl_exit();
        unregister_key_type(&key_type_rxrpc_s);
        unregister_key_type(&key_type_rxrpc);
        sock_unregister(PF_RXRPC);
index cd97a0ce48d80f73efbf2476e272f737c787bad9..c6be17a959a6e4981ecfff38af85805df6d8b26e 100644 (file)
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
-static unsigned int rxrpc_ack_defer = 1;
+/*
+ * How long to wait before scheduling ACK generation after seeing a
+ * packet with RXRPC_REQUEST_ACK set (in jiffies).
+ */
+unsigned rxrpc_requested_ack_delay = 1;
+
+/*
+ * How long to wait before scheduling an ACK with subtype DELAY (in jiffies).
+ *
+ * We use this when we've received new data packets.  If those packets aren't
+ * all consumed within this time we will send a DELAY ACK if an ACK was not
+ * requested to let the sender know it doesn't need to resend.
+ */
+unsigned rxrpc_soft_ack_delay = 1 * HZ;
+
+/*
+ * How long to wait before scheduling an ACK with subtype IDLE (in jiffies).
+ *
+ * We use this when we've consumed some previously soft-ACK'd packets when
+ * further packets aren't immediately received to decide when to send an IDLE
+ * ACK let the other end know that it can free up its Tx buffer space.
+ */
+unsigned rxrpc_idle_ack_delay = 0.5 * HZ;
+
+/*
+ * Receive window size in packets.  This indicates the maximum number of
+ * unconsumed received packets we're willing to retain in memory.  Once this
+ * limit is hit, we should generate an EXCEEDS_WINDOW ACK and discard further
+ * packets.
+ */
+unsigned rxrpc_rx_window_size = 32;
+
+/*
+ * Maximum Rx MTU size.  This indicates to the sender the size of jumbo packet
+ * made by gluing normal packets together that we're willing to handle.
+ */
+unsigned rxrpc_rx_mtu = 5692;
+
+/*
+ * The maximum number of fragments in a received jumbo packet that we tell the
+ * sender that we're willing to handle.
+ */
+unsigned rxrpc_rx_jumbo_max = 4;
 
 static const char *rxrpc_acks(u8 reason)
 {
@@ -82,24 +124,23 @@ void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
        switch (ack_reason) {
        case RXRPC_ACK_DELAY:
                _debug("run delay timer");
-               call->ack_timer.expires = jiffies + rxrpc_ack_timeout * HZ;
-               add_timer(&call->ack_timer);
-               return;
+               expiry = rxrpc_soft_ack_delay;
+               goto run_timer;
 
        case RXRPC_ACK_IDLE:
                if (!immediate) {
                        _debug("run defer timer");
-                       expiry = 1;
+                       expiry = rxrpc_idle_ack_delay;
                        goto run_timer;
                }
                goto cancel_timer;
 
        case RXRPC_ACK_REQUESTED:
-               if (!rxrpc_ack_defer)
+               expiry = rxrpc_requested_ack_delay;
+               if (!expiry)
                        goto cancel_timer;
                if (!immediate || serial == cpu_to_be32(1)) {
                        _debug("run defer timer");
-                       expiry = rxrpc_ack_defer;
                        goto run_timer;
                }
 
@@ -1174,11 +1215,11 @@ send_ACK:
        mtu = call->conn->trans->peer->if_mtu;
        mtu -= call->conn->trans->peer->hdrsize;
        ackinfo.maxMTU  = htonl(mtu);
-       ackinfo.rwind   = htonl(32);
+       ackinfo.rwind   = htonl(rxrpc_rx_window_size);
 
        /* permit the peer to send us jumbo packets if it wants to */
-       ackinfo.rxMTU   = htonl(5692);
-       ackinfo.jumbo_max = htonl(4);
+       ackinfo.rxMTU   = htonl(rxrpc_rx_mtu);
+       ackinfo.jumbo_max = htonl(rxrpc_rx_jumbo_max);
 
        hdr.serial = htonl(atomic_inc_return(&call->conn->serial));
        _proto("Tx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
index a3bbb360a3f96e0ee4aa6aac2e7eea830305b564..a9e05db0f5d5900e93f87a8567e7533a1745c82a 100644 (file)
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/circ_buf.h>
+#include <linux/hashtable.h>
+#include <linux/spinlock_types.h>
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
+/*
+ * Maximum lifetime of a call (in jiffies).
+ */
+unsigned rxrpc_max_call_lifetime = 60 * HZ;
+
+/*
+ * Time till dead call expires after last use (in jiffies).
+ */
+unsigned rxrpc_dead_call_expiry = 2 * HZ;
+
 const char *const rxrpc_call_states[] = {
        [RXRPC_CALL_CLIENT_SEND_REQUEST]        = "ClSndReq",
        [RXRPC_CALL_CLIENT_AWAIT_REPLY]         = "ClAwtRpl",
@@ -38,8 +50,6 @@ const char *const rxrpc_call_states[] = {
 struct kmem_cache *rxrpc_call_jar;
 LIST_HEAD(rxrpc_calls);
 DEFINE_RWLOCK(rxrpc_call_lock);
-static unsigned int rxrpc_call_max_lifetime = 60;
-static unsigned int rxrpc_dead_call_timeout = 2;
 
 static void rxrpc_destroy_call(struct work_struct *work);
 static void rxrpc_call_life_expired(unsigned long _call);
@@ -47,6 +57,145 @@ static void rxrpc_dead_call_expired(unsigned long _call);
 static void rxrpc_ack_time_expired(unsigned long _call);
 static void rxrpc_resend_time_expired(unsigned long _call);
 
+static DEFINE_SPINLOCK(rxrpc_call_hash_lock);
+static DEFINE_HASHTABLE(rxrpc_call_hash, 10);
+
+/*
+ * Hash function for rxrpc_call_hash
+ */
+static unsigned long rxrpc_call_hashfunc(
+       u8              clientflag,
+       __be32          cid,
+       __be32          call_id,
+       __be32          epoch,
+       __be16          service_id,
+       sa_family_t     proto,
+       void            *localptr,
+       unsigned int    addr_size,
+       const u8        *peer_addr)
+{
+       const u16 *p;
+       unsigned int i;
+       unsigned long key;
+       u32 hcid = ntohl(cid);
+
+       _enter("");
+
+       key = (unsigned long)localptr;
+       /* We just want to add up the __be32 values, so forcing the
+        * cast should be okay.
+        */
+       key += (__force u32)epoch;
+       key += (__force u16)service_id;
+       key += (__force u32)call_id;
+       key += (hcid & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT;
+       key += hcid & RXRPC_CHANNELMASK;
+       key += clientflag;
+       key += proto;
+       /* Step through the peer address in 16-bit portions for speed */
+       for (i = 0, p = (const u16 *)peer_addr; i < addr_size >> 1; i++, p++)
+               key += *p;
+       _leave(" key = 0x%lx", key);
+       return key;
+}
+
+/*
+ * Add a call to the hashtable
+ */
+static void rxrpc_call_hash_add(struct rxrpc_call *call)
+{
+       unsigned long key;
+       unsigned int addr_size = 0;
+
+       _enter("");
+       switch (call->proto) {
+       case AF_INET:
+               addr_size = sizeof(call->peer_ip.ipv4_addr);
+               break;
+       case AF_INET6:
+               addr_size = sizeof(call->peer_ip.ipv6_addr);
+               break;
+       default:
+               break;
+       }
+       key = rxrpc_call_hashfunc(call->in_clientflag, call->cid,
+                                 call->call_id, call->epoch,
+                                 call->service_id, call->proto,
+                                 call->conn->trans->local, addr_size,
+                                 call->peer_ip.ipv6_addr);
+       /* Store the full key in the call */
+       call->hash_key = key;
+       spin_lock(&rxrpc_call_hash_lock);
+       hash_add_rcu(rxrpc_call_hash, &call->hash_node, key);
+       spin_unlock(&rxrpc_call_hash_lock);
+       _leave("");
+}
+
+/*
+ * Remove a call from the hashtable
+ */
+static void rxrpc_call_hash_del(struct rxrpc_call *call)
+{
+       _enter("");
+       spin_lock(&rxrpc_call_hash_lock);
+       hash_del_rcu(&call->hash_node);
+       spin_unlock(&rxrpc_call_hash_lock);
+       _leave("");
+}
+
+/*
+ * Find a call in the hashtable and return it, or NULL if it
+ * isn't there.
+ */
+struct rxrpc_call *rxrpc_find_call_hash(
+       u8              clientflag,
+       __be32          cid,
+       __be32          call_id,
+       __be32          epoch,
+       __be16          service_id,
+       void            *localptr,
+       sa_family_t     proto,
+       const u8        *peer_addr)
+{
+       unsigned long key;
+       unsigned int addr_size = 0;
+       struct rxrpc_call *call = NULL;
+       struct rxrpc_call *ret = NULL;
+
+       _enter("");
+       switch (proto) {
+       case AF_INET:
+               addr_size = sizeof(call->peer_ip.ipv4_addr);
+               break;
+       case AF_INET6:
+               addr_size = sizeof(call->peer_ip.ipv6_addr);
+               break;
+       default:
+               break;
+       }
+
+       key = rxrpc_call_hashfunc(clientflag, cid, call_id, epoch,
+                                 service_id, proto, localptr, addr_size,
+                                 peer_addr);
+       hash_for_each_possible_rcu(rxrpc_call_hash, call, hash_node, key) {
+               if (call->hash_key == key &&
+                   call->call_id == call_id &&
+                   call->cid == cid &&
+                   call->in_clientflag == clientflag &&
+                   call->service_id == service_id &&
+                   call->proto == proto &&
+                   call->local == localptr &&
+                   memcmp(call->peer_ip.ipv6_addr, peer_addr,
+                             addr_size) == 0 &&
+                   call->epoch == epoch) {
+                       ret = call;
+                       break;
+               }
+       }
+       _leave(" = %p", ret);
+       return ret;
+}
+
 /*
  * allocate a new call
  */
@@ -91,7 +240,7 @@ static struct rxrpc_call *rxrpc_alloc_call(gfp_t gfp)
        call->rx_data_expect = 1;
        call->rx_data_eaten = 0;
        call->rx_first_oos = 0;
-       call->ackr_win_top = call->rx_data_eaten + 1 + RXRPC_MAXACKS;
+       call->ackr_win_top = call->rx_data_eaten + 1 + rxrpc_rx_window_size;
        call->creation_jif = jiffies;
        return call;
 }
@@ -128,11 +277,31 @@ static struct rxrpc_call *rxrpc_alloc_client_call(
                return ERR_PTR(ret);
        }
 
+       /* Record copies of information for hashtable lookup */
+       call->proto = rx->proto;
+       call->local = trans->local;
+       switch (call->proto) {
+       case AF_INET:
+               call->peer_ip.ipv4_addr =
+                       trans->peer->srx.transport.sin.sin_addr.s_addr;
+               break;
+       case AF_INET6:
+               memcpy(call->peer_ip.ipv6_addr,
+                      trans->peer->srx.transport.sin6.sin6_addr.in6_u.u6_addr8,
+                      sizeof(call->peer_ip.ipv6_addr));
+               break;
+       }
+       call->epoch = call->conn->epoch;
+       call->service_id = call->conn->service_id;
+       call->in_clientflag = call->conn->in_clientflag;
+       /* Add the new call to the hashtable */
+       rxrpc_call_hash_add(call);
+
        spin_lock(&call->conn->trans->peer->lock);
        list_add(&call->error_link, &call->conn->trans->peer->error_targets);
        spin_unlock(&call->conn->trans->peer->lock);
 
-       call->lifetimer.expires = jiffies + rxrpc_call_max_lifetime * HZ;
+       call->lifetimer.expires = jiffies + rxrpc_max_call_lifetime;
        add_timer(&call->lifetimer);
 
        _leave(" = %p", call);
@@ -320,9 +489,12 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
                parent = *p;
                call = rb_entry(parent, struct rxrpc_call, conn_node);
 
-               if (call_id < call->call_id)
+               /* The tree is sorted in order of the __be32 value without
+                * turning it into host order.
+                */
+               if ((__force u32)call_id < (__force u32)call->call_id)
                        p = &(*p)->rb_left;
-               else if (call_id > call->call_id)
+               else if ((__force u32)call_id > (__force u32)call->call_id)
                        p = &(*p)->rb_right;
                else
                        goto old_call;
@@ -347,9 +519,31 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
        list_add_tail(&call->link, &rxrpc_calls);
        write_unlock_bh(&rxrpc_call_lock);
 
+       /* Record copies of information for hashtable lookup */
+       call->proto = rx->proto;
+       call->local = conn->trans->local;
+       switch (call->proto) {
+       case AF_INET:
+               call->peer_ip.ipv4_addr =
+                       conn->trans->peer->srx.transport.sin.sin_addr.s_addr;
+               break;
+       case AF_INET6:
+               memcpy(call->peer_ip.ipv6_addr,
+                      conn->trans->peer->srx.transport.sin6.sin6_addr.in6_u.u6_addr8,
+                      sizeof(call->peer_ip.ipv6_addr));
+               break;
+       default:
+               break;
+       }
+       call->epoch = conn->epoch;
+       call->service_id = conn->service_id;
+       call->in_clientflag = conn->in_clientflag;
+       /* Add the new call to the hashtable */
+       rxrpc_call_hash_add(call);
+
        _net("CALL incoming %d on CONN %d", call->debug_id, call->conn->debug_id);
 
-       call->lifetimer.expires = jiffies + rxrpc_call_max_lifetime * HZ;
+       call->lifetimer.expires = jiffies + rxrpc_max_call_lifetime;
        add_timer(&call->lifetimer);
        _leave(" = %p {%d} [new]", call, call->debug_id);
        return call;
@@ -533,7 +727,7 @@ void rxrpc_release_call(struct rxrpc_call *call)
        del_timer_sync(&call->resend_timer);
        del_timer_sync(&call->ack_timer);
        del_timer_sync(&call->lifetimer);
-       call->deadspan.expires = jiffies + rxrpc_dead_call_timeout * HZ;
+       call->deadspan.expires = jiffies + rxrpc_dead_call_expiry;
        add_timer(&call->deadspan);
 
        _leave("");
@@ -665,6 +859,9 @@ static void rxrpc_cleanup_call(struct rxrpc_call *call)
                rxrpc_put_connection(call->conn);
        }
 
+       /* Remove the call from the hash */
+       rxrpc_call_hash_del(call);
+
        if (call->acks_window) {
                _debug("kill Tx window %d",
                       CIRC_CNT(call->acks_head, call->acks_tail,
index 7bf5b5b9e8b9400af1cbaecaeaf9a8c222670492..6631f4f1e39be713029c8b9b504db4ea741fb3e6 100644 (file)
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
+/*
+ * Time till a connection expires after last use (in seconds).
+ */
+unsigned rxrpc_connection_expiry = 10 * 60;
+
 static void rxrpc_connection_reaper(struct work_struct *work);
 
 LIST_HEAD(rxrpc_connections);
 DEFINE_RWLOCK(rxrpc_connection_lock);
-static unsigned long rxrpc_connection_timeout = 10 * 60;
 static DECLARE_DELAYED_WORK(rxrpc_connection_reap, rxrpc_connection_reaper);
 
 /*
@@ -862,7 +866,7 @@ static void rxrpc_connection_reaper(struct work_struct *work)
 
                spin_lock(&conn->trans->client_lock);
                write_lock(&conn->trans->conn_lock);
-               reap_time = conn->put_time + rxrpc_connection_timeout;
+               reap_time = conn->put_time + rxrpc_connection_expiry;
 
                if (atomic_read(&conn->usage) > 0) {
                        ;
@@ -916,7 +920,7 @@ void __exit rxrpc_destroy_all_connections(void)
 {
        _enter("");
 
-       rxrpc_connection_timeout = 0;
+       rxrpc_connection_expiry = 0;
        cancel_delayed_work(&rxrpc_connection_reap);
        rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
 
index a9206087b4d7a87ced5cef6c77b69fc2bb86a11c..db57458c824c87b463ceff200be22c07df936b73 100644 (file)
@@ -83,6 +83,7 @@ void rxrpc_UDP_error_report(struct sock *sk)
 
                if (mtu == 0) {
                        /* they didn't give us a size, estimate one */
+                       mtu = peer->if_mtu;
                        if (mtu > 1500) {
                                mtu >>= 1;
                                if (mtu < 1500)
index 529572f18d1fa56b71a3154c9d822445fffef358..73742647c1354ebc76cdc44289fcc5948ca188ac 100644 (file)
@@ -25,8 +25,6 @@
 #include <net/net_namespace.h>
 #include "ar-internal.h"
 
-unsigned long rxrpc_ack_timeout = 1;
-
 const char *rxrpc_pkts[] = {
        "?00",
        "DATA", "ACK", "BUSY", "ABORT", "ACKALL", "CHALL", "RESP", "DEBUG",
@@ -349,8 +347,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
         * it */
        if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
                _proto("ACK Requested on %%%u", serial);
-               rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial,
-                                 !(sp->hdr.flags & RXRPC_MORE_PACKETS));
+               rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial, false);
        }
 
        switch (sp->hdr.type) {
@@ -526,36 +523,38 @@ protocol_error:
  * post an incoming packet to the appropriate call/socket to deal with
  * - must get rid of the sk_buff, either by freeing it or by queuing it
  */
-static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn,
+static void rxrpc_post_packet_to_call(struct rxrpc_call *call,
                                      struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp;
-       struct rxrpc_call *call;
-       struct rb_node *p;
-       __be32 call_id;
-
-       _enter("%p,%p", conn, skb);
 
-       read_lock_bh(&conn->lock);
+       _enter("%p,%p", call, skb);
 
        sp = rxrpc_skb(skb);
 
-       /* look at extant calls by channel number first */
-       call = conn->channels[ntohl(sp->hdr.cid) & RXRPC_CHANNELMASK];
-       if (!call || call->call_id != sp->hdr.callNumber)
-               goto call_not_extant;
-
        _debug("extant call [%d]", call->state);
-       ASSERTCMP(call->conn, ==, conn);
 
        read_lock(&call->state_lock);
        switch (call->state) {
        case RXRPC_CALL_LOCALLY_ABORTED:
-               if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events))
+               if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events)) {
                        rxrpc_queue_call(call);
+                       goto free_unlock;
+               }
        case RXRPC_CALL_REMOTELY_ABORTED:
        case RXRPC_CALL_NETWORK_ERROR:
        case RXRPC_CALL_DEAD:
+               goto dead_call;
+       case RXRPC_CALL_COMPLETE:
+       case RXRPC_CALL_CLIENT_FINAL_ACK:
+               /* complete server call */
+               if (call->conn->in_clientflag)
+                       goto dead_call;
+               /* resend last packet of a completed call */
+               _debug("final ack again");
+               rxrpc_get_call(call);
+               set_bit(RXRPC_CALL_ACK_FINAL, &call->events);
+               rxrpc_queue_call(call);
                goto free_unlock;
        default:
                break;
@@ -563,7 +562,6 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn,
 
        read_unlock(&call->state_lock);
        rxrpc_get_call(call);
-       read_unlock_bh(&conn->lock);
 
        if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
            sp->hdr.flags & RXRPC_JUMBO_PACKET)
@@ -574,78 +572,16 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn,
        rxrpc_put_call(call);
        goto done;
 
-call_not_extant:
-       /* search the completed calls in case what we're dealing with is
-        * there */
-       _debug("call not extant");
-
-       call_id = sp->hdr.callNumber;
-       p = conn->calls.rb_node;
-       while (p) {
-               call = rb_entry(p, struct rxrpc_call, conn_node);
-
-               if (call_id < call->call_id)
-                       p = p->rb_left;
-               else if (call_id > call->call_id)
-                       p = p->rb_right;
-               else
-                       goto found_completed_call;
-       }
-
 dead_call:
-       /* it's a either a really old call that we no longer remember or its a
-        * new incoming call */
-       read_unlock_bh(&conn->lock);
-
-       if (sp->hdr.flags & RXRPC_CLIENT_INITIATED &&
-           sp->hdr.seq == cpu_to_be32(1)) {
-               _debug("incoming call");
-               skb_queue_tail(&conn->trans->local->accept_queue, skb);
-               rxrpc_queue_work(&conn->trans->local->acceptor);
-               goto done;
-       }
-
-       _debug("dead call");
-       skb->priority = RX_CALL_DEAD;
-       rxrpc_reject_packet(conn->trans->local, skb);
-       goto done;
-
-       /* resend last packet of a completed call
-        * - client calls may have been aborted or ACK'd
-        * - server calls may have been aborted
-        */
-found_completed_call:
-       _debug("completed call");
-
-       if (atomic_read(&call->usage) == 0)
-               goto dead_call;
-
-       /* synchronise any state changes */
-       read_lock(&call->state_lock);
-       ASSERTIFCMP(call->state != RXRPC_CALL_CLIENT_FINAL_ACK,
-                   call->state, >=, RXRPC_CALL_COMPLETE);
-
-       if (call->state == RXRPC_CALL_LOCALLY_ABORTED ||
-           call->state == RXRPC_CALL_REMOTELY_ABORTED ||
-           call->state == RXRPC_CALL_DEAD) {
-               read_unlock(&call->state_lock);
-               goto dead_call;
-       }
-
-       if (call->conn->in_clientflag) {
-               read_unlock(&call->state_lock);
-               goto dead_call; /* complete server call */
+       if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) {
+               skb->priority = RX_CALL_DEAD;
+               rxrpc_reject_packet(call->conn->trans->local, skb);
+               goto unlock;
        }
-
-       _debug("final ack again");
-       rxrpc_get_call(call);
-       set_bit(RXRPC_CALL_ACK_FINAL, &call->events);
-       rxrpc_queue_call(call);
-
 free_unlock:
-       read_unlock(&call->state_lock);
-       read_unlock_bh(&conn->lock);
        rxrpc_free_skb(skb);
+unlock:
+       read_unlock(&call->state_lock);
 done:
        _leave("");
 }
@@ -664,17 +600,42 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
        rxrpc_queue_conn(conn);
 }
 
+static struct rxrpc_connection *rxrpc_conn_from_local(struct rxrpc_local *local,
+                                              struct sk_buff *skb,
+                                              struct rxrpc_skb_priv *sp)
+{
+       struct rxrpc_peer *peer;
+       struct rxrpc_transport *trans;
+       struct rxrpc_connection *conn;
+
+       peer = rxrpc_find_peer(local, ip_hdr(skb)->saddr,
+                               udp_hdr(skb)->source);
+       if (IS_ERR(peer))
+               goto cant_find_conn;
+
+       trans = rxrpc_find_transport(local, peer);
+       rxrpc_put_peer(peer);
+       if (!trans)
+               goto cant_find_conn;
+
+       conn = rxrpc_find_connection(trans, &sp->hdr);
+       rxrpc_put_transport(trans);
+       if (!conn)
+               goto cant_find_conn;
+
+       return conn;
+cant_find_conn:
+       return NULL;
+}
+
 /*
  * handle data received on the local endpoint
  * - may be called in interrupt context
  */
 void rxrpc_data_ready(struct sock *sk, int count)
 {
-       struct rxrpc_connection *conn;
-       struct rxrpc_transport *trans;
        struct rxrpc_skb_priv *sp;
        struct rxrpc_local *local;
-       struct rxrpc_peer *peer;
        struct sk_buff *skb;
        int ret;
 
@@ -749,27 +710,34 @@ void rxrpc_data_ready(struct sock *sk, int count)
            (sp->hdr.callNumber == 0 || sp->hdr.seq == 0))
                goto bad_message;
 
-       peer = rxrpc_find_peer(local, ip_hdr(skb)->saddr, udp_hdr(skb)->source);
-       if (IS_ERR(peer))
-               goto cant_route_call;
+       if (sp->hdr.callNumber == 0) {
+               /* This is a connection-level packet. These should be
+                * fairly rare, so the extra overhead of looking them up the
+                * old-fashioned way doesn't really hurt */
+               struct rxrpc_connection *conn;
 
-       trans = rxrpc_find_transport(local, peer);
-       rxrpc_put_peer(peer);
-       if (!trans)
-               goto cant_route_call;
+               conn = rxrpc_conn_from_local(local, skb, sp);
+               if (!conn)
+                       goto cant_route_call;
 
-       conn = rxrpc_find_connection(trans, &sp->hdr);
-       rxrpc_put_transport(trans);
-       if (!conn)
-               goto cant_route_call;
-
-       _debug("CONN %p {%d}", conn, conn->debug_id);
-
-       if (sp->hdr.callNumber == 0)
+               _debug("CONN %p {%d}", conn, conn->debug_id);
                rxrpc_post_packet_to_conn(conn, skb);
-       else
-               rxrpc_post_packet_to_call(conn, skb);
-       rxrpc_put_connection(conn);
+               rxrpc_put_connection(conn);
+       } else {
+               struct rxrpc_call *call;
+               u8 in_clientflag = 0;
+
+               if (sp->hdr.flags & RXRPC_CLIENT_INITIATED)
+                       in_clientflag = RXRPC_CLIENT_INITIATED;
+               call = rxrpc_find_call_hash(in_clientflag, sp->hdr.cid,
+                                           sp->hdr.callNumber, sp->hdr.epoch,
+                                           sp->hdr.serviceId, local, AF_INET,
+                                           (u8 *)&ip_hdr(skb)->saddr);
+               if (call)
+                       rxrpc_post_packet_to_call(call, skb);
+               else
+                       goto cant_route_call;
+       }
        rxrpc_put_local(local);
        return;
 
@@ -790,8 +758,10 @@ cant_route_call:
                skb->priority = RX_CALL_DEAD;
        }
 
-       _debug("reject");
-       rxrpc_reject_packet(local, skb);
+       if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) {
+               _debug("reject type %d",sp->hdr.type);
+               rxrpc_reject_packet(local, skb);
+       }
        rxrpc_put_local(local);
        _leave(" [no call]");
        return;
index 5f43675ee1df3822ecf98e432797f9b498047b58..c831d44b0841a07233c20881a1fc516ab425041d 100644 (file)
@@ -396,9 +396,20 @@ struct rxrpc_call {
 #define RXRPC_ACKR_WINDOW_ASZ DIV_ROUND_UP(RXRPC_MAXACKS, BITS_PER_LONG)
        unsigned long           ackr_window[RXRPC_ACKR_WINDOW_ASZ + 1];
 
+       struct hlist_node       hash_node;
+       unsigned long           hash_key;       /* Full hash key */
+       u8                      in_clientflag;  /* Copy of conn->in_clientflag for hashing */
+       struct rxrpc_local      *local;         /* Local endpoint. Used for hashing. */
+       sa_family_t             proto;          /* Frame protocol */
        /* the following should all be in net order */
        __be32                  cid;            /* connection ID + channel index  */
        __be32                  call_id;        /* call ID on connection  */
+       __be32                  epoch;          /* epoch of this connection */
+       __be16                  service_id;     /* service ID */
+       union {                                 /* Peer IP address for hashing */
+               __be32  ipv4_addr;
+               __u8    ipv6_addr[16];          /* Anticipates eventual IPv6 support */
+       } peer_ip;
 };
 
 /*
@@ -433,6 +444,13 @@ int rxrpc_reject_call(struct rxrpc_sock *);
 /*
  * ar-ack.c
  */
+extern unsigned rxrpc_requested_ack_delay;
+extern unsigned rxrpc_soft_ack_delay;
+extern unsigned rxrpc_idle_ack_delay;
+extern unsigned rxrpc_rx_window_size;
+extern unsigned rxrpc_rx_mtu;
+extern unsigned rxrpc_rx_jumbo_max;
+
 void __rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool);
 void rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool);
 void rxrpc_process_call(struct work_struct *);
@@ -440,10 +458,14 @@ void rxrpc_process_call(struct work_struct *);
 /*
  * ar-call.c
  */
+extern unsigned rxrpc_max_call_lifetime;
+extern unsigned rxrpc_dead_call_expiry;
 extern struct kmem_cache *rxrpc_call_jar;
 extern struct list_head rxrpc_calls;
 extern rwlock_t rxrpc_call_lock;
 
+struct rxrpc_call *rxrpc_find_call_hash(u8,  __be32, __be32, __be32,
+                                       __be16, void *, sa_family_t, const u8 *);
 struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *,
                                         struct rxrpc_transport *,
                                         struct rxrpc_conn_bundle *,
@@ -460,6 +482,7 @@ void __exit rxrpc_destroy_all_calls(void);
 /*
  * ar-connection.c
  */
+extern unsigned rxrpc_connection_expiry;
 extern struct list_head rxrpc_connections;
 extern rwlock_t rxrpc_connection_lock;
 
@@ -493,7 +516,6 @@ void rxrpc_UDP_error_handler(struct work_struct *);
 /*
  * ar-input.c
  */
-extern unsigned long rxrpc_ack_timeout;
 extern const char *rxrpc_pkts[];
 
 void rxrpc_data_ready(struct sock *, int);
@@ -504,6 +526,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *, struct sk_buff *);
  * ar-local.c
  */
 extern rwlock_t rxrpc_local_lock;
+
 struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *);
 void rxrpc_put_local(struct rxrpc_local *);
 void __exit rxrpc_destroy_all_locals(void);
@@ -522,7 +545,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, time_t,
 /*
  * ar-output.c
  */
-extern int rxrpc_resend_timeout;
+extern unsigned rxrpc_resend_timeout;
 
 int rxrpc_send_packet(struct rxrpc_transport *, struct sk_buff *);
 int rxrpc_client_sendmsg(struct kiocb *, struct rxrpc_sock *,
@@ -572,6 +595,8 @@ void rxrpc_packet_destructor(struct sk_buff *);
 /*
  * ar-transport.c
  */
+extern unsigned rxrpc_transport_expiry;
+
 struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *,
                                            struct rxrpc_peer *, gfp_t);
 void rxrpc_put_transport(struct rxrpc_transport *);
@@ -579,6 +604,17 @@ void __exit rxrpc_destroy_all_transports(void);
 struct rxrpc_transport *rxrpc_find_transport(struct rxrpc_local *,
                                             struct rxrpc_peer *);
 
+/*
+ * sysctl.c
+ */
+#ifdef CONFIG_SYSCTL
+extern int __init rxrpc_sysctl_init(void);
+extern void rxrpc_sysctl_exit(void);
+#else
+static inline int __init rxrpc_sysctl_init(void) { return 0; }
+static inline void rxrpc_sysctl_exit(void) {}
+#endif
+
 /*
  * debug tracing
  */
index d0e8f1c1898a092437bb035208c9c616f16a17ae..0b4b9a79f5abd0fb24e413551550aba25e7ce8e4 100644 (file)
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
-int rxrpc_resend_timeout = 4;
+/*
+ * Time till packet resend (in jiffies).
+ */
+unsigned rxrpc_resend_timeout = 4 * HZ;
 
 static int rxrpc_send_data(struct kiocb *iocb,
                           struct rxrpc_sock *rx,
@@ -487,7 +490,7 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
               ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
 
        sp->need_resend = false;
-       sp->resend_at = jiffies + rxrpc_resend_timeout * HZ;
+       sp->resend_at = jiffies + rxrpc_resend_timeout;
        if (!test_and_set_bit(RXRPC_CALL_RUN_RTIMER, &call->flags)) {
                _debug("run timer");
                call->resend_timer.expires = sp->resend_at;
@@ -666,6 +669,7 @@ static int rxrpc_send_data(struct kiocb *iocb,
                /* add the packet to the send queue if it's now full */
                if (sp->remain <= 0 || (segment == 0 && !more)) {
                        struct rxrpc_connection *conn = call->conn;
+                       uint32_t seq;
                        size_t pad;
 
                        /* pad out if we're using security */
@@ -678,11 +682,12 @@ static int rxrpc_send_data(struct kiocb *iocb,
                                        memset(skb_put(skb, pad), 0, pad);
                        }
 
+                       seq = atomic_inc_return(&call->sequence);
+
                        sp->hdr.epoch = conn->epoch;
                        sp->hdr.cid = call->cid;
                        sp->hdr.callNumber = call->call_id;
-                       sp->hdr.seq =
-                               htonl(atomic_inc_return(&call->sequence));
+                       sp->hdr.seq = htonl(seq);
                        sp->hdr.serial =
                                htonl(atomic_inc_return(&conn->serial));
                        sp->hdr.type = RXRPC_PACKET_TYPE_DATA;
@@ -697,6 +702,8 @@ static int rxrpc_send_data(struct kiocb *iocb,
                        else if (CIRC_SPACE(call->acks_head, call->acks_tail,
                                            call->acks_winsz) > 1)
                                sp->hdr.flags |= RXRPC_MORE_PACKETS;
+                       if (more && seq & 1)
+                               sp->hdr.flags |= RXRPC_REQUEST_ACK;
 
                        ret = rxrpc_secure_packet(
                                call, skb, skb->mark,
index 34b5490dde655ccdbac5dcbbc7b0df1b88ab42ca..e9aaa65c07784cf9991f5bef279e4dab49a6912f 100644 (file)
@@ -180,16 +180,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
                if (copy > len - copied)
                        copy = len - copied;
 
-               if (skb->ip_summed == CHECKSUM_UNNECESSARY ||
-                   skb->ip_summed == CHECKSUM_PARTIAL) {
-                       ret = skb_copy_datagram_iovec(skb, offset,
-                                                     msg->msg_iov, copy);
-               } else {
-                       ret = skb_copy_and_csum_datagram_iovec(skb, offset,
-                                                              msg->msg_iov);
-                       if (ret == -EINVAL)
-                               goto csum_copy_error;
-               }
+               ret = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copy);
 
                if (ret < 0)
                        goto copy_error;
@@ -348,20 +339,6 @@ copy_error:
        _leave(" = %d", ret);
        return ret;
 
-csum_copy_error:
-       _debug("csum error");
-       release_sock(&rx->sk);
-       if (continue_call)
-               rxrpc_put_call(continue_call);
-       rxrpc_kill_skb(skb);
-       if (!(flags & MSG_PEEK)) {
-               if (skb_dequeue(&rx->sk.sk_receive_queue) != skb)
-                       BUG();
-       }
-       skb_kill_datagram(&rx->sk, skb, flags);
-       rxrpc_put_call(call);
-       return -EAGAIN;
-
 wait_interrupted:
        ret = sock_intr_errno(timeo);
 wait_error:
index de755e04d29ce1495a0f0c9459b487da85c0b413..4cfab49e329dbba1a2cfa05c1faeff66fd016031 100644 (file)
@@ -83,9 +83,14 @@ static void rxrpc_hard_ACK_data(struct rxrpc_call *call,
                rxrpc_request_final_ACK(call);
        } else if (atomic_dec_and_test(&call->ackr_not_idle) &&
                   test_and_clear_bit(RXRPC_CALL_TX_SOFT_ACK, &call->flags)) {
+               /* We previously soft-ACK'd some received packets that have now
+                * been consumed, so send a hard-ACK if no more packets are
+                * immediately forthcoming to allow the transmitter to free up
+                * its Tx bufferage.
+                */
                _debug("send Rx idle ACK");
                __rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, sp->hdr.serial,
-                                   true);
+                                   false);
        }
 
        spin_unlock_bh(&call->lock);
index 92df566930b9a05c23d109cb9e42806698cbb535..1976dec84f297cfb126df6bcd53129f1d518001b 100644 (file)
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
+/*
+ * Time after last use at which transport record is cleaned up.
+ */
+unsigned rxrpc_transport_expiry = 3600 * 24;
+
 static void rxrpc_transport_reaper(struct work_struct *work);
 
 static LIST_HEAD(rxrpc_transports);
 static DEFINE_RWLOCK(rxrpc_transport_lock);
-static unsigned long rxrpc_transport_timeout = 3600 * 24;
 static DECLARE_DELAYED_WORK(rxrpc_transport_reap, rxrpc_transport_reaper);
 
 /*
@@ -235,7 +239,7 @@ static void rxrpc_transport_reaper(struct work_struct *work)
                if (likely(atomic_read(&trans->usage) > 0))
                        continue;
 
-               reap_time = trans->put_time + rxrpc_transport_timeout;
+               reap_time = trans->put_time + rxrpc_transport_expiry;
                if (reap_time <= now)
                        list_move_tail(&trans->link, &graveyard);
                else if (reap_time < earliest)
@@ -271,7 +275,7 @@ void __exit rxrpc_destroy_all_transports(void)
 {
        _enter("");
 
-       rxrpc_transport_timeout = 0;
+       rxrpc_transport_expiry = 0;
        cancel_delayed_work(&rxrpc_transport_reap);
        rxrpc_queue_delayed_work(&rxrpc_transport_reap, 0);
 
diff --git a/net/rxrpc/sysctl.c b/net/rxrpc/sysctl.c
new file mode 100644 (file)
index 0000000..50a98a9
--- /dev/null
@@ -0,0 +1,146 @@
+/* sysctls for configuring RxRPC operating parameters
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/sysctl.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+static struct ctl_table_header *rxrpc_sysctl_reg_table;
+static const unsigned zero = 0;
+static const unsigned one = 1;
+static const unsigned four = 4;
+static const unsigned n_65535 = 65535;
+static const unsigned n_max_acks = RXRPC_MAXACKS;
+
+/*
+ * RxRPC operating parameters.
+ *
+ * See Documentation/networking/rxrpc.txt and the variable definitions for more
+ * information on the individual parameters.
+ */
+static struct ctl_table rxrpc_sysctl_table[] = {
+       /* Values measured in milliseconds */
+       {
+               .procname       = "req_ack_delay",
+               .data           = &rxrpc_requested_ack_delay,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ms_jiffies,
+               .extra1         = (void *)&zero,
+       },
+       {
+               .procname       = "soft_ack_delay",
+               .data           = &rxrpc_soft_ack_delay,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ms_jiffies,
+               .extra1         = (void *)&one,
+       },
+       {
+               .procname       = "idle_ack_delay",
+               .data           = &rxrpc_idle_ack_delay,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ms_jiffies,
+               .extra1         = (void *)&one,
+       },
+       {
+               .procname       = "resend_timeout",
+               .data           = &rxrpc_resend_timeout,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ms_jiffies,
+               .extra1         = (void *)&one,
+       },
+
+       /* Values measured in seconds but used in jiffies */
+       {
+               .procname       = "max_call_lifetime",
+               .data           = &rxrpc_max_call_lifetime,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_jiffies,
+               .extra1         = (void *)&one,
+       },
+       {
+               .procname       = "dead_call_expiry",
+               .data           = &rxrpc_dead_call_expiry,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_jiffies,
+               .extra1         = (void *)&one,
+       },
+
+       /* Values measured in seconds */
+       {
+               .procname       = "connection_expiry",
+               .data           = &rxrpc_connection_expiry,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+       },
+       {
+               .procname       = "transport_expiry",
+               .data           = &rxrpc_transport_expiry,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+       },
+
+       /* Non-time values */
+       {
+               .procname       = "rx_window_size",
+               .data           = &rxrpc_rx_window_size,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+               .extra2         = (void *)&n_max_acks,
+       },
+       {
+               .procname       = "rx_mtu",
+               .data           = &rxrpc_rx_mtu,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+               .extra1         = (void *)&n_65535,
+       },
+       {
+               .procname       = "rx_jumbo_max",
+               .data           = &rxrpc_rx_jumbo_max,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+               .extra2         = (void *)&four,
+       },
+
+       { }
+};
+
+int __init rxrpc_sysctl_init(void)
+{
+       rxrpc_sysctl_reg_table = register_net_sysctl(&init_net, "net/rxrpc",
+                                                    rxrpc_sysctl_table);
+       if (!rxrpc_sysctl_reg_table)
+               return -ENOMEM;
+       return 0;
+}
+
+void rxrpc_sysctl_exit(void)
+{
+       if (rxrpc_sysctl_reg_table)
+               unregister_net_sysctl_table(rxrpc_sysctl_reg_table);
+}
index 1313145e3b8650853514552a0ddb371b4000b788..a0b84e0e22deb4c9e998499b1e202ebaafda95f8 100644 (file)
@@ -273,11 +273,12 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
 
 void qdisc_list_add(struct Qdisc *q)
 {
-       struct Qdisc *root = qdisc_dev(q)->qdisc;
+       if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
+               struct Qdisc *root = qdisc_dev(q)->qdisc;
 
-       WARN_ON_ONCE(root == &noop_qdisc);
-       if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
+               WARN_ON_ONCE(root == &noop_qdisc);
                list_add_tail(&q->list, &root->list);
+       }
 }
 EXPORT_SYMBOL(qdisc_list_add);
 
@@ -1303,6 +1304,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
        struct gnet_dump d;
        struct qdisc_size_table *stab;
 
+       cond_resched();
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
        if (!nlh)
                goto out_nlmsg_trim;
@@ -1434,9 +1436,9 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
        s_idx = cb->args[0];
        s_q_idx = q_idx = cb->args[1];
 
-       rcu_read_lock();
        idx = 0;
-       for_each_netdev_rcu(net, dev) {
+       ASSERT_RTNL();
+       for_each_netdev(net, dev) {
                struct netdev_queue *dev_queue;
 
                if (idx < s_idx)
@@ -1459,8 +1461,6 @@ cont:
        }
 
 done:
-       rcu_read_unlock();
-
        cb->args[0] = idx;
        cb->args[1] = q_idx;
 
@@ -1617,6 +1617,7 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
        struct gnet_dump d;
        const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops;
 
+       cond_resched();
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
        if (!nlh)
                goto out_nlmsg_trim;
index 1f9c31411f1998dec927fccf05362f09408558b4..8449b337f9e3c9991b36144b98965a08d463cdf9 100644 (file)
@@ -623,8 +623,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
                if (nla_put_u32(skb, TCA_ATM_EXCESS, 0))
                        goto nla_put_failure;
        }
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
index 2f80d01d42a6d8b971345229d407f062df921b04..ead526467ccae574d6afddb7a5146fc7507e68a9 100644 (file)
@@ -1563,8 +1563,7 @@ static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb)
                goto nla_put_failure;
        if (cbq_dump_attr(skb, &q->link) < 0)
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
@@ -1599,8 +1598,7 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg,
                goto nla_put_failure;
        if (cbq_dump_attr(skb, cl) < 0)
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
index 08ef7a42c0e411657e789cb140fad522aef97ed1..23c682b42f99ecb86ca8a103005a52d692a21d38 100644 (file)
@@ -601,6 +601,7 @@ static int fq_resize(struct Qdisc *sch, u32 log)
 {
        struct fq_sched_data *q = qdisc_priv(sch);
        struct rb_root *array;
+       void *old_fq_root;
        u32 idx;
 
        if (q->fq_root && log == q->fq_trees_log)
@@ -615,13 +616,19 @@ static int fq_resize(struct Qdisc *sch, u32 log)
        for (idx = 0; idx < (1U << log); idx++)
                array[idx] = RB_ROOT;
 
-       if (q->fq_root) {
-               fq_rehash(q, q->fq_root, q->fq_trees_log, array, log);
-               fq_free(q->fq_root);
-       }
+       sch_tree_lock(sch);
+
+       old_fq_root = q->fq_root;
+       if (old_fq_root)
+               fq_rehash(q, old_fq_root, q->fq_trees_log, array, log);
+
        q->fq_root = array;
        q->fq_trees_log = log;
 
+       sch_tree_unlock(sch);
+
+       fq_free(old_fq_root);
+
        return 0;
 }
 
@@ -697,9 +704,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
                q->flow_refill_delay = usecs_to_jiffies(usecs_delay);
        }
 
-       if (!err)
+       if (!err) {
+               sch_tree_unlock(sch);
                err = fq_resize(sch, fq_log);
-
+               sch_tree_lock(sch);
+       }
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = fq_dequeue(sch);
 
@@ -772,8 +781,7 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb)
            nla_put_u32(skb, TCA_FQ_BUCKETS_LOG, q->fq_trees_log))
                goto nla_put_failure;
 
-       nla_nest_end(skb, opts);
-       return skb->len;
+       return nla_nest_end(skb, opts);
 
 nla_put_failure:
        return -1;
index ba5bc929eac732900c1d6e3150ad224f3a50a1ae..0bf432c782c1f17cdb8bbb1b8ece16848e63c27e 100644 (file)
@@ -450,8 +450,7 @@ static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb)
                        q->flows_cnt))
                goto nla_put_failure;
 
-       nla_nest_end(skb, opts);
-       return skb->len;
+       return nla_nest_end(skb, opts);
 
 nla_put_failure:
        return -1;
index c4075610502cf3f53f4ac3f1bc1be7b096e7f488..ec8aeaac1dd7ad7a077fddac3535c18064351b77 100644 (file)
@@ -1353,8 +1353,7 @@ hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb,
                goto nla_put_failure;
        if (hfsc_dump_curves(skb, cl) < 0)
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
  nla_put_failure:
        nla_nest_cancel(skb, nest);
index 647680b1c625ec9ca41adff446cd2bc32bc76a54..edee03d922e28678cc4f4ba843f600236cf06f08 100644 (file)
@@ -691,8 +691,7 @@ static int hhf_dump(struct Qdisc *sch, struct sk_buff *skb)
            nla_put_u32(skb, TCA_HHF_NON_HH_WEIGHT, q->hhf_non_hh_weight))
                goto nla_put_failure;
 
-       nla_nest_end(skb, opts);
-       return skb->len;
+       return nla_nest_end(skb, opts);
 
 nla_put_failure:
        return -1;
index 722e137df244dfef1fbd1ab8e8b477546990acde..9f949abcacef1680dcdc15579c7fe56611f21852 100644 (file)
@@ -1062,12 +1062,13 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
 
 static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
-       spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
        struct htb_sched *q = qdisc_priv(sch);
        struct nlattr *nest;
        struct tc_htb_glob gopt;
 
-       spin_lock_bh(root_lock);
+       /* Its safe to not acquire qdisc lock. As we hold RTNL,
+        * no change can happen on the qdisc parameters.
+        */
 
        gopt.direct_pkts = q->direct_pkts;
        gopt.version = HTB_VER;
@@ -1081,13 +1082,10 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
        if (nla_put(skb, TCA_HTB_INIT, sizeof(gopt), &gopt) ||
            nla_put_u32(skb, TCA_HTB_DIRECT_QLEN, q->direct_qlen))
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
 
-       spin_unlock_bh(root_lock);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
-       spin_unlock_bh(root_lock);
        nla_nest_cancel(skb, nest);
        return -1;
 }
@@ -1096,11 +1094,12 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
                          struct sk_buff *skb, struct tcmsg *tcm)
 {
        struct htb_class *cl = (struct htb_class *)arg;
-       spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
        struct nlattr *nest;
        struct tc_htb_opt opt;
 
-       spin_lock_bh(root_lock);
+       /* Its safe to not acquire qdisc lock. As we hold RTNL,
+        * no change can happen on the class parameters.
+        */
        tcm->tcm_parent = cl->parent ? cl->parent->common.classid : TC_H_ROOT;
        tcm->tcm_handle = cl->common.classid;
        if (!cl->level && cl->un.leaf.q)
@@ -1128,12 +1127,9 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
            nla_put_u64(skb, TCA_HTB_CEIL64, cl->ceil.rate_bytes_ps))
                goto nla_put_failure;
 
-       nla_nest_end(skb, nest);
-       spin_unlock_bh(root_lock);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
-       spin_unlock_bh(root_lock);
        nla_nest_cancel(skb, nest);
        return -1;
 }
index bce1665239b8ff7e55901b216fb705bd6b31229e..62871c14e1f93fef31e5795ad2b8ae2f064399a4 100644 (file)
@@ -100,8 +100,7 @@ static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
        nest = nla_nest_start(skb, TCA_OPTIONS);
        if (nest == NULL)
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
index 0893161b0262d217d4917198df4bfc3d61839346..18ff634337092d5f8e7cba8fe817542f1455738f 100644 (file)
@@ -338,18 +338,6 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
                        qdisc_put_rtab(qdisc_get_rtab(&qopt->peakrate,
                                                      tb[TCA_TBF_PTAB]));
 
-       if (q->qdisc != &noop_qdisc) {
-               err = fifo_set_limit(q->qdisc, qopt->limit);
-               if (err)
-                       goto done;
-       } else if (qopt->limit > 0) {
-               child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
-               if (IS_ERR(child)) {
-                       err = PTR_ERR(child);
-                       goto done;
-               }
-       }
-
        buffer = min_t(u64, PSCHED_TICKS2NS(qopt->buffer), ~0U);
        mtu = min_t(u64, PSCHED_TICKS2NS(qopt->mtu), ~0U);
 
@@ -396,6 +384,18 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
                goto done;
        }
 
+       if (q->qdisc != &noop_qdisc) {
+               err = fifo_set_limit(q->qdisc, qopt->limit);
+               if (err)
+                       goto done;
+       } else if (qopt->limit > 0) {
+               child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
+               if (IS_ERR(child)) {
+                       err = PTR_ERR(child);
+                       goto done;
+               }
+       }
+
        sch_tree_lock(sch);
        if (child) {
                qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
@@ -475,8 +475,7 @@ static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
            nla_put_u64(skb, TCA_TBF_PRATE64, q->peak.rate_bytes_ps))
                goto nla_put_failure;
 
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
index f558433537b8f829a3f6147256abb7c5d23e4b47..4f6d6f9d127474b457cf274a1a0977bb75c6e8dc 100644 (file)
@@ -1239,78 +1239,106 @@ void sctp_assoc_update(struct sctp_association *asoc,
 }
 
 /* Update the retran path for sending a retransmitted packet.
- * Round-robin through the active transports, else round-robin
- * through the inactive transports as this is the next best thing
- * we can try.
+ * See also RFC4960, 6.4. Multi-Homed SCTP Endpoints:
+ *
+ *   When there is outbound data to send and the primary path
+ *   becomes inactive (e.g., due to failures), or where the
+ *   SCTP user explicitly requests to send data to an
+ *   inactive destination transport address, before reporting
+ *   an error to its ULP, the SCTP endpoint should try to send
+ *   the data to an alternate active destination transport
+ *   address if one exists.
+ *
+ *   When retransmitting data that timed out, if the endpoint
+ *   is multihomed, it should consider each source-destination
+ *   address pair in its retransmission selection policy.
+ *   When retransmitting timed-out data, the endpoint should
+ *   attempt to pick the most divergent source-destination
+ *   pair from the original source-destination pair to which
+ *   the packet was transmitted.
+ *
+ *   Note: Rules for picking the most divergent source-destination
+ *   pair are an implementation decision and are not specified
+ *   within this document.
+ *
+ * Our basic strategy is to round-robin transports in priorities
+ * according to sctp_state_prio_map[] e.g., if no such
+ * transport with state SCTP_ACTIVE exists, round-robin through
+ * SCTP_UNKNOWN, etc. You get the picture.
  */
-void sctp_assoc_update_retran_path(struct sctp_association *asoc)
+static const u8 sctp_trans_state_to_prio_map[] = {
+       [SCTP_ACTIVE]   = 3,    /* best case */
+       [SCTP_UNKNOWN]  = 2,
+       [SCTP_PF]       = 1,
+       [SCTP_INACTIVE] = 0,    /* worst case */
+};
+
+static u8 sctp_trans_score(const struct sctp_transport *trans)
 {
-       struct sctp_transport *t, *next;
-       struct list_head *head = &asoc->peer.transport_addr_list;
-       struct list_head *pos;
+       return sctp_trans_state_to_prio_map[trans->state];
+}
 
-       if (asoc->peer.transport_count == 1)
-               return;
+static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr,
+                                                   struct sctp_transport *best)
+{
+       if (best == NULL)
+               return curr;
 
-       /* Find the next transport in a round-robin fashion. */
-       t = asoc->peer.retran_path;
-       pos = &t->transports;
-       next = NULL;
+       return sctp_trans_score(curr) > sctp_trans_score(best) ? curr : best;
+}
 
-       while (1) {
-               /* Skip the head. */
-               if (pos->next == head)
-                       pos = head->next;
-               else
-                       pos = pos->next;
+void sctp_assoc_update_retran_path(struct sctp_association *asoc)
+{
+       struct sctp_transport *trans = asoc->peer.retran_path;
+       struct sctp_transport *trans_next = NULL;
 
-               t = list_entry(pos, struct sctp_transport, transports);
+       /* We're done as we only have the one and only path. */
+       if (asoc->peer.transport_count == 1)
+               return;
+       /* If active_path and retran_path are the same and active,
+        * then this is the only active path. Use it.
+        */
+       if (asoc->peer.active_path == asoc->peer.retran_path &&
+           asoc->peer.active_path->state == SCTP_ACTIVE)
+               return;
 
-               /* We have exhausted the list, but didn't find any
-                * other active transports.  If so, use the next
-                * transport.
-                */
-               if (t == asoc->peer.retran_path) {
-                       t = next;
+       /* Iterate from retran_path's successor back to retran_path. */
+       for (trans = list_next_entry(trans, transports); 1;
+            trans = list_next_entry(trans, transports)) {
+               /* Manually skip the head element. */
+               if (&trans->transports == &asoc->peer.transport_addr_list)
+                       continue;
+               if (trans->state == SCTP_UNCONFIRMED)
+                       continue;
+               trans_next = sctp_trans_elect_best(trans, trans_next);
+               /* Active is good enough for immediate return. */
+               if (trans_next->state == SCTP_ACTIVE)
                        break;
-               }
-
-               /* Try to find an active transport. */
-
-               if ((t->state == SCTP_ACTIVE) ||
-                   (t->state == SCTP_UNKNOWN)) {
+               /* We've reached the end, time to update path. */
+               if (trans == asoc->peer.retran_path)
                        break;
-               } else {
-                       /* Keep track of the next transport in case
-                        * we don't find any active transport.
-                        */
-                       if (t->state != SCTP_UNCONFIRMED && !next)
-                               next = t;
-               }
        }
 
-       if (t)
-               asoc->peer.retran_path = t;
-       else
-               t = asoc->peer.retran_path;
+       asoc->peer.retran_path = trans_next;
 
-       pr_debug("%s: association:%p addr:%pISpc\n", __func__, asoc,
-                &t->ipaddr.sa);
+       pr_debug("%s: association:%p updated new path to addr:%pISpc\n",
+                __func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
 }
 
-/* Choose the transport for sending retransmit packet.  */
-struct sctp_transport *sctp_assoc_choose_alter_transport(
-       struct sctp_association *asoc, struct sctp_transport *last_sent_to)
+struct sctp_transport *
+sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
+                                 struct sctp_transport *last_sent_to)
 {
        /* If this is the first time packet is sent, use the active path,
         * else use the retran path. If the last packet was sent over the
         * retran path, update the retran path and use it.
         */
-       if (!last_sent_to)
+       if (last_sent_to == NULL) {
                return asoc->peer.active_path;
-       else {
+       else {
                if (last_sent_to == asoc->peer.retran_path)
                        sctp_assoc_update_retran_path(asoc);
+
                return asoc->peer.retran_path;
        }
 }
index 632090b961c331b78efa79664392c7626451926d..3a1767ef3201a6a1870f641ef29e3683ea6dcff7 100644 (file)
@@ -1421,8 +1421,8 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
        BUG_ON(!list_empty(&chunk->list));
        list_del_init(&chunk->transmitted_list);
 
-       /* Free the chunk skb data and the SCTP_chunk stub itself. */
-       dev_kfree_skb(chunk->skb);
+       consume_skb(chunk->skb);
+       consume_skb(chunk->auth_chunk);
 
        SCTP_DBG_OBJCNT_DEC(chunk);
        kmem_cache_free(sctp_chunk_cachep, chunk);
index bd859154000e47cccdae4f9f5e4353ba3cb83fd0..5d6883ff00c3b7056639f06254caffcb14349e27 100644 (file)
@@ -495,11 +495,12 @@ static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands,
        }
 
        /* If the transport error count is greater than the pf_retrans
-        * threshold, and less than pathmaxrtx, then mark this transport
-        * as Partially Failed, ee SCTP Quick Failover Draft, secon 5.1,
-        * point 1
+        * threshold, and less than pathmaxrtx, and if the current state
+        * is not SCTP_UNCONFIRMED, then mark this transport as Partially
+        * Failed, see SCTP Quick Failover Draft, section 5.1
         */
        if ((transport->state != SCTP_PF) &&
+          (transport->state != SCTP_UNCONFIRMED) &&
           (asoc->pf_retrans < transport->pathmaxrxt) &&
           (transport->error_count > asoc->pf_retrans)) {
 
index 591b44d3b7de6bb39faa994cddc72851422ec08f..01e002430c858c293cdda11bd2962c3340043fb9 100644 (file)
@@ -758,6 +758,12 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
                struct sctp_chunk auth;
                sctp_ierror_t ret;
 
+               /* Make sure that we and the peer are AUTH capable */
+               if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
+                       sctp_association_free(new_asoc);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+               }
+
                /* set-up our fake chunk so that we can process it */
                auth.skb = chunk->auth_chunk;
                auth.asoc = chunk->asoc;
@@ -768,10 +774,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
                auth.transport = chunk->transport;
 
                ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
-
-               /* We can now safely free the auth_chunk clone */
-               kfree_skb(chunk->auth_chunk);
-
                if (ret != SCTP_IERROR_NO_ERROR) {
                        sctp_association_free(new_asoc);
                        return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
index 840cffb7119b2d927316583de76c623a63d2478b..f25eaa30b6907dd9d8c332c54a05cc38c843f7ff 100644 (file)
@@ -450,16 +450,17 @@ EXPORT_SYMBOL(sockfd_lookup);
 
 static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
 {
-       struct file *file;
+       struct fd f = fdget(fd);
        struct socket *sock;
 
        *err = -EBADF;
-       file = fget_light(fd, fput_needed);
-       if (file) {
-               sock = sock_from_file(file, err);
-               if (sock)
+       if (f.file) {
+               sock = sock_from_file(f.file, err);
+               if (likely(sock)) {
+                       *fput_needed = f.flags;
                        return sock;
-               fput_light(file, *fput_needed);
+               }
+               fdput(f);
        }
        return NULL;
 }
@@ -1985,6 +1986,10 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
 {
        if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
                return -EFAULT;
+
+       if (kmsg->msg_namelen < 0)
+               return -EINVAL;
+
        if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
        return 0;
index 6c0513a7f99232280f78067d56c5c369cb79630d..36e431ee1c902ef1c6ed777331cf97ceda0bdee4 100644 (file)
@@ -108,6 +108,7 @@ struct gss_auth {
 static DEFINE_SPINLOCK(pipe_version_lock);
 static struct rpc_wait_queue pipe_version_rpc_waitqueue;
 static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
+static void gss_put_auth(struct gss_auth *gss_auth);
 
 static void gss_free_ctx(struct gss_cl_ctx *);
 static const struct rpc_pipe_ops gss_upcall_ops_v0;
@@ -320,6 +321,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
        if (gss_msg->ctx != NULL)
                gss_put_ctx(gss_msg->ctx);
        rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
+       gss_put_auth(gss_msg->auth);
        kfree(gss_msg);
 }
 
@@ -498,9 +500,12 @@ gss_alloc_msg(struct gss_auth *gss_auth,
        default:
                err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
                if (err)
-                       goto err_free_msg;
+                       goto err_put_pipe_version;
        };
+       kref_get(&gss_auth->kref);
        return gss_msg;
+err_put_pipe_version:
+       put_pipe_version(gss_auth->net);
 err_free_msg:
        kfree(gss_msg);
 err:
@@ -991,6 +996,8 @@ gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
        gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
        if (gss_auth->service == 0)
                goto err_put_mech;
+       if (!gssd_running(gss_auth->net))
+               goto err_put_mech;
        auth = &gss_auth->rpc_auth;
        auth->au_cslack = GSS_CRED_SLACK >> 2;
        auth->au_rslack = GSS_VERF_SLACK >> 2;
@@ -1061,6 +1068,12 @@ gss_free_callback(struct kref *kref)
        gss_free(gss_auth);
 }
 
+static void
+gss_put_auth(struct gss_auth *gss_auth)
+{
+       kref_put(&gss_auth->kref, gss_free_callback);
+}
+
 static void
 gss_destroy(struct rpc_auth *auth)
 {
@@ -1082,7 +1095,7 @@ gss_destroy(struct rpc_auth *auth)
        gss_auth->gss_pipe[1] = NULL;
        rpcauth_destroy_credcache(auth);
 
-       kref_put(&gss_auth->kref, gss_free_callback);
+       gss_put_auth(gss_auth);
 }
 
 /*
@@ -1253,7 +1266,7 @@ gss_destroy_nullcred(struct rpc_cred *cred)
        call_rcu(&cred->cr_rcu, gss_free_cred_callback);
        if (ctx)
                gss_put_ctx(ctx);
-       kref_put(&gss_auth->kref, gss_free_callback);
+       gss_put_auth(gss_auth);
 }
 
 static void
index 890a29912d5ab3f39d156891d4844ede04d367e8..e860d4f7ed2accd100c9ae9f715018daaae469a1 100644 (file)
@@ -64,7 +64,6 @@ static void xprt_free_allocation(struct rpc_rqst *req)
        free_page((unsigned long)xbufp->head[0].iov_base);
        xbufp = &req->rq_snd_buf;
        free_page((unsigned long)xbufp->head[0].iov_base);
-       list_del(&req->rq_bc_pa_list);
        kfree(req);
 }
 
@@ -168,8 +167,10 @@ out_free:
        /*
         * Memory allocation failed, free the temporary list
         */
-       list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list)
+       list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) {
+               list_del(&req->rq_bc_pa_list);
                xprt_free_allocation(req);
+       }
 
        dprintk("RPC:       setup backchannel transport failed\n");
        return -ENOMEM;
@@ -198,6 +199,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
        xprt_dec_alloc_count(xprt, max_reqs);
        list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) {
                dprintk("RPC:        req=%p\n", req);
+               list_del(&req->rq_bc_pa_list);
                xprt_free_allocation(req);
                if (--max_reqs == 0)
                        break;
index 817a1e5239692e9fb3f5117f36eb0895d426ea5f..0addefca8e7757d78571928580d6f7473a1354ae 100644 (file)
@@ -510,6 +510,7 @@ static int xs_nospace(struct rpc_task *task)
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       struct sock *sk = transport->inet;
        int ret = -EAGAIN;
 
        dprintk("RPC: %5u xmit incomplete (%u left of %u)\n",
@@ -527,7 +528,7 @@ static int xs_nospace(struct rpc_task *task)
                         * window size
                         */
                        set_bit(SOCK_NOSPACE, &transport->sock->flags);
-                       transport->inet->sk_write_pending++;
+                       sk->sk_write_pending++;
                        /* ...and wait for more buffer space */
                        xprt_wait_for_buffer_space(task, xs_nospace_callback);
                }
@@ -537,6 +538,9 @@ static int xs_nospace(struct rpc_task *task)
        }
 
        spin_unlock_bh(&xprt->transport_lock);
+
+       /* Race breaker in case memory is freed before above code is called */
+       sk->sk_write_space(sk);
        return ret;
 }
 
index 242cddd35a474707ff8c569bf239fdbe1b76df35..7f1f95c57476a05623afad7f65863b508db3436a 100644 (file)
@@ -575,7 +575,7 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
 }
 
 static struct packet_type tipc_packet_type __read_mostly = {
-       .type = __constant_htons(ETH_P_TIPC),
+       .type = htons(ETH_P_TIPC),
        .func = tipc_l2_rcv_msg,
 };
 
@@ -586,8 +586,13 @@ static struct notifier_block notifier = {
 
 int tipc_bearer_setup(void)
 {
+       int err;
+
+       err = register_netdevice_notifier(&notifier);
+       if (err)
+               return err;
        dev_add_pack(&tipc_packet_type);
-       return register_netdevice_notifier(&notifier);
+       return 0;
 }
 
 void tipc_bearer_cleanup(void)
index c301a9a592d82d570050116df07e54a4551da537..e6d721692ae016bbc900ac909406ca0a645848b0 100644 (file)
@@ -181,7 +181,7 @@ static struct sk_buff *cfg_set_own_addr(void)
        if (tipc_own_addr)
                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                   " (cannot change node address once assigned)");
-       tipc_core_start_net(addr);
+       tipc_net_start(addr);
        return tipc_cfg_reply_none();
 }
 
@@ -376,7 +376,6 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
        struct tipc_cfg_msg_hdr *req_hdr;
        struct tipc_cfg_msg_hdr *rep_hdr;
        struct sk_buff *rep_buf;
-       int ret;
 
        /* Validate configuration message header (ignore invalid message) */
        req_hdr = (struct tipc_cfg_msg_hdr *)buf;
@@ -398,12 +397,8 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
                memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
                rep_hdr->tcm_len = htonl(rep_buf->len);
                rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
-
-               ret = tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
-                                       rep_buf->len);
-               if (ret < 0)
-                       pr_err("Sending cfg reply message failed, no memory\n");
-
+               tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
+                                 rep_buf->len);
                kfree_skb(rep_buf);
        }
 }
index 3f76b98d2feda1fa7c19072cbbe16e1788f109f0..e2491b341edb16982d2d64a2d4c3883a061d4155 100644 (file)
@@ -76,38 +76,14 @@ struct sk_buff *tipc_buf_acquire(u32 size)
        return skb;
 }
 
-/**
- * tipc_core_stop_net - shut down TIPC networking sub-systems
- */
-static void tipc_core_stop_net(void)
-{
-       tipc_net_stop();
-       tipc_bearer_cleanup();
-}
-
-/**
- * start_net - start TIPC networking sub-systems
- */
-int tipc_core_start_net(unsigned long addr)
-{
-       int res;
-
-       tipc_net_start(addr);
-       res = tipc_bearer_setup();
-       if (res < 0)
-               goto err;
-       return res;
-
-err:
-       tipc_core_stop_net();
-       return res;
-}
-
 /**
  * tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
  */
 static void tipc_core_stop(void)
 {
+       tipc_handler_stop();
+       tipc_net_stop();
+       tipc_bearer_cleanup();
        tipc_netlink_stop();
        tipc_cfg_stop();
        tipc_subscr_stop();
@@ -122,30 +98,65 @@ static void tipc_core_stop(void)
  */
 static int tipc_core_start(void)
 {
-       int res;
+       int err;
 
        get_random_bytes(&tipc_random, sizeof(tipc_random));
 
-       res = tipc_handler_start();
-       if (!res)
-               res = tipc_ref_table_init(tipc_max_ports, tipc_random);
-       if (!res)
-               res = tipc_nametbl_init();
-       if (!res)
-               res = tipc_netlink_start();
-       if (!res)
-               res = tipc_socket_init();
-       if (!res)
-               res = tipc_register_sysctl();
-       if (!res)
-               res = tipc_subscr_start();
-       if (!res)
-               res = tipc_cfg_init();
-       if (res) {
-               tipc_handler_stop();
-               tipc_core_stop();
-       }
-       return res;
+       err = tipc_handler_start();
+       if (err)
+               goto out_handler;
+
+       err = tipc_ref_table_init(tipc_max_ports, tipc_random);
+       if (err)
+               goto out_reftbl;
+
+       err = tipc_nametbl_init();
+       if (err)
+               goto out_nametbl;
+
+       err = tipc_netlink_start();
+       if (err)
+               goto out_netlink;
+
+       err = tipc_socket_init();
+       if (err)
+               goto out_socket;
+
+       err = tipc_register_sysctl();
+       if (err)
+               goto out_sysctl;
+
+       err = tipc_subscr_start();
+       if (err)
+               goto out_subscr;
+
+       err = tipc_cfg_init();
+       if (err)
+               goto out_cfg;
+
+       err = tipc_bearer_setup();
+       if (err)
+               goto out_bearer;
+
+       return 0;
+out_bearer:
+       tipc_cfg_stop();
+out_cfg:
+       tipc_subscr_stop();
+out_subscr:
+       tipc_unregister_sysctl();
+out_sysctl:
+       tipc_socket_stop();
+out_socket:
+       tipc_netlink_stop();
+out_netlink:
+       tipc_nametbl_stop();
+out_nametbl:
+       tipc_ref_table_stop();
+out_reftbl:
+       tipc_handler_stop();
+out_handler:
+       return err;
 }
 
 static int __init tipc_init(void)
@@ -174,8 +185,6 @@ static int __init tipc_init(void)
 
 static void __exit tipc_exit(void)
 {
-       tipc_handler_stop();
-       tipc_core_stop_net();
        tipc_core_stop();
        pr_info("Deactivated\n");
 }
index 5569d96b4da3f3652bd418656a2f7e81822feda4..4dfe137587bbd35a519b87a107f4e665a625bdaa 100644 (file)
@@ -90,7 +90,6 @@ extern int tipc_random __read_mostly;
 /*
  * Routines available to privileged subsystems
  */
-int tipc_core_start_net(unsigned long);
 int tipc_handler_start(void);
 void tipc_handler_stop(void);
 int tipc_netlink_start(void);
index e4bc8a2967447fbde1f39d0d19146f2c7848ac99..1fabf160501f4f7b8127ef8d8a7583076e9b2eb4 100644 (file)
@@ -58,7 +58,6 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument)
 
        spin_lock_bh(&qitem_lock);
        if (!handler_enabled) {
-               pr_err("Signal request ignored by handler\n");
                spin_unlock_bh(&qitem_lock);
                return -ENOPROTOOPT;
        }
index d1a764b9b2d81a2374e8a01235e345adb0f18c48..a42f4a1d3cd1d4cd2acd2251a1ab6000660cb3d1 100644 (file)
@@ -327,8 +327,6 @@ static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz)
        spin_lock_bh(&tipc_port_list_lock);
        p_ptr = tipc_port_lock(origport);
        if (p_ptr) {
-               if (!p_ptr->wakeup)
-                       goto exit;
                if (!list_empty(&p_ptr->wait_list))
                        goto exit;
                p_ptr->congested = 1;
@@ -363,7 +361,7 @@ void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all)
                list_del_init(&p_ptr->wait_list);
                spin_lock_bh(p_ptr->lock);
                p_ptr->congested = 0;
-               p_ptr->wakeup(p_ptr);
+               tipc_port_wakeup(p_ptr);
                win -= p_ptr->waiting_pkts;
                spin_unlock_bh(p_ptr->lock);
        }
index 92a1533af4e0a689f93f30c5b560368f1a548e37..042e8e3cabc09f84aa5dce626c57a30faf3ca32d 100644 (file)
@@ -941,20 +941,48 @@ int tipc_nametbl_init(void)
        return 0;
 }
 
-void tipc_nametbl_stop(void)
+/**
+ * tipc_purge_publications - remove all publications for a given type
+ *
+ * tipc_nametbl_lock must be held when calling this function
+ */
+static void tipc_purge_publications(struct name_seq *seq)
 {
-       u32 i;
+       struct publication *publ, *safe;
+       struct sub_seq *sseq;
+       struct name_info *info;
 
-       if (!table.types)
+       if (!seq->sseqs) {
+               nameseq_delete_empty(seq);
                return;
+       }
+       sseq = seq->sseqs;
+       info = sseq->info;
+       list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
+               tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
+                                        publ->ref, publ->key);
+       }
+}
+
+void tipc_nametbl_stop(void)
+{
+       u32 i;
+       struct name_seq *seq;
+       struct hlist_head *seq_head;
+       struct hlist_node *safe;
 
-       /* Verify name table is empty, then release it */
+       /* Verify name table is empty and purge any lingering
+        * publications, then release the name table
+        */
        write_lock_bh(&tipc_nametbl_lock);
        for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
                if (hlist_empty(&table.types[i]))
                        continue;
-               pr_err("nametbl_stop(): orphaned hash chain detected\n");
-               break;
+               seq_head = &table.types[i];
+               hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) {
+                       tipc_purge_publications(seq);
+               }
+               continue;
        }
        kfree(table.types);
        table.types = NULL;
index 9f72a6376362e613cb87185acbb3581174c45592..3aaf73de9e2d017e96b3cc1124d5c9420d827abd 100644 (file)
@@ -83,8 +83,6 @@ static struct genl_ops tipc_genl_ops[] = {
        },
 };
 
-static int tipc_genl_family_registered;
-
 int tipc_netlink_start(void)
 {
        int res;
@@ -94,16 +92,10 @@ int tipc_netlink_start(void)
                pr_err("Failed to register netlink interface\n");
                return res;
        }
-
-       tipc_genl_family_registered = 1;
        return 0;
 }
 
 void tipc_netlink_stop(void)
 {
-       if (!tipc_genl_family_registered)
-               return;
-
        genl_unregister_family(&tipc_genl_family);
-       tipc_genl_family_registered = 0;
 }
index c7c2b549a39e8b7ce5ff00d6cce73793217025bc..5c14c7801ee65095d809d502cab9f78d33d51e5e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/port.c: TIPC port code
  *
- * Copyright (c) 1992-2007, Ericsson AB
+ * Copyright (c) 1992-2007, 2014, Ericsson AB
  * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
  * All rights reserved.
  *
@@ -38,6 +38,7 @@
 #include "config.h"
 #include "port.h"
 #include "name_table.h"
+#include "socket.h"
 
 /* Connection management: */
 #define PROBING_INTERVAL 3600000       /* [ms] => 1 h */
@@ -54,17 +55,6 @@ static struct sk_buff *port_build_self_abort_msg(struct tipc_port *, u32 err);
 static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);
 static void port_timeout(unsigned long ref);
 
-
-static u32 port_peernode(struct tipc_port *p_ptr)
-{
-       return msg_destnode(&p_ptr->phdr);
-}
-
-static u32 port_peerport(struct tipc_port *p_ptr)
-{
-       return msg_destport(&p_ptr->phdr);
-}
-
 /**
  * tipc_port_peer_msg - verify message was sent by connected port's peer
  *
@@ -76,11 +66,11 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
        u32 peernode;
        u32 orignode;
 
-       if (msg_origport(msg) != port_peerport(p_ptr))
+       if (msg_origport(msg) != tipc_port_peerport(p_ptr))
                return 0;
 
        orignode = msg_orignode(msg);
-       peernode = port_peernode(p_ptr);
+       peernode = tipc_port_peernode(p_ptr);
        return (orignode == peernode) ||
                (!orignode && (peernode == tipc_own_addr)) ||
                (!peernode && (orignode == tipc_own_addr));
@@ -90,20 +80,18 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
  * tipc_port_mcast_xmit - send a multicast message to local and remote
  * destinations
  */
-int tipc_port_mcast_xmit(u32 ref, struct tipc_name_seq const *seq,
-                        struct iovec const *msg_sect, unsigned int len)
+int tipc_port_mcast_xmit(struct tipc_port *oport,
+                        struct tipc_name_seq const *seq,
+                        struct iovec const *msg_sect,
+                        unsigned int len)
 {
        struct tipc_msg *hdr;
        struct sk_buff *buf;
        struct sk_buff *ibuf = NULL;
        struct tipc_port_list dports = {0, NULL, };
-       struct tipc_port *oport = tipc_port_deref(ref);
        int ext_targets;
        int res;
 
-       if (unlikely(!oport))
-               return -EINVAL;
-
        /* Create multicast message */
        hdr = &oport->phdr;
        msg_set_type(hdr, TIPC_MCAST_MSG);
@@ -200,40 +188,32 @@ exit:
        tipc_port_list_free(dp);
 }
 
-/**
- * tipc_createport - create a generic TIPC port
+
+void tipc_port_wakeup(struct tipc_port *port)
+{
+       tipc_sock_wakeup(tipc_port_to_sock(port));
+}
+
+/* tipc_port_init - intiate TIPC port and lock it
  *
- * Returns pointer to (locked) TIPC port, or NULL if unable to create it
+ * Returns obtained reference if initialization is successful, zero otherwise
  */
-struct tipc_port *tipc_createport(struct sock *sk,
-                                 u32 (*dispatcher)(struct tipc_port *,
-                                 struct sk_buff *),
-                                 void (*wakeup)(struct tipc_port *),
-                                 const u32 importance)
+u32 tipc_port_init(struct tipc_port *p_ptr,
+                  const unsigned int importance)
 {
-       struct tipc_port *p_ptr;
        struct tipc_msg *msg;
        u32 ref;
 
-       p_ptr = kzalloc(sizeof(*p_ptr), GFP_ATOMIC);
-       if (!p_ptr) {
-               pr_warn("Port creation failed, no memory\n");
-               return NULL;
-       }
        ref = tipc_ref_acquire(p_ptr, &p_ptr->lock);
        if (!ref) {
-               pr_warn("Port creation failed, ref. table exhausted\n");
-               kfree(p_ptr);
-               return NULL;
+               pr_warn("Port registration failed, ref. table exhausted\n");
+               return 0;
        }
 
-       p_ptr->sk = sk;
        p_ptr->max_pkt = MAX_PKT_DEFAULT;
        p_ptr->ref = ref;
        INIT_LIST_HEAD(&p_ptr->wait_list);
        INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
-       p_ptr->dispatcher = dispatcher;
-       p_ptr->wakeup = wakeup;
        k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
        INIT_LIST_HEAD(&p_ptr->publications);
        INIT_LIST_HEAD(&p_ptr->port_list);
@@ -249,10 +229,10 @@ struct tipc_port *tipc_createport(struct sock *sk,
        msg_set_origport(msg, ref);
        list_add_tail(&p_ptr->port_list, &ports);
        spin_unlock_bh(&tipc_port_list_lock);
-       return p_ptr;
+       return ref;
 }
 
-int tipc_deleteport(struct tipc_port *p_ptr)
+void tipc_port_destroy(struct tipc_port *p_ptr)
 {
        struct sk_buff *buf = NULL;
 
@@ -273,67 +253,7 @@ int tipc_deleteport(struct tipc_port *p_ptr)
        list_del(&p_ptr->wait_list);
        spin_unlock_bh(&tipc_port_list_lock);
        k_term_timer(&p_ptr->timer);
-       kfree(p_ptr);
        tipc_net_route_msg(buf);
-       return 0;
-}
-
-static int port_unreliable(struct tipc_port *p_ptr)
-{
-       return msg_src_droppable(&p_ptr->phdr);
-}
-
-int tipc_portunreliable(u32 ref, unsigned int *isunreliable)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       *isunreliable = port_unreliable(p_ptr);
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-int tipc_set_portunreliable(u32 ref, unsigned int isunreliable)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       msg_set_src_droppable(&p_ptr->phdr, (isunreliable != 0));
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-static int port_unreturnable(struct tipc_port *p_ptr)
-{
-       return msg_dest_droppable(&p_ptr->phdr);
-}
-
-int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       *isunrejectable = port_unreturnable(p_ptr);
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       msg_set_dest_droppable(&p_ptr->phdr, (isunrejectable != 0));
-       tipc_port_unlock(p_ptr);
-       return 0;
 }
 
 /*
@@ -351,8 +271,8 @@ static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr,
        if (buf) {
                msg = buf_msg(buf);
                tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE,
-                             port_peernode(p_ptr));
-               msg_set_destport(msg, port_peerport(p_ptr));
+                             tipc_port_peernode(p_ptr));
+               msg_set_destport(msg, tipc_port_peerport(p_ptr));
                msg_set_origport(msg, p_ptr->ref);
                msg_set_msgcnt(msg, ack);
        }
@@ -548,13 +468,12 @@ void tipc_port_proto_rcv(struct sk_buff *buf)
        /* Process protocol message sent by peer */
        switch (msg_type(msg)) {
        case CONN_ACK:
-               wakeable = tipc_port_congested(p_ptr) && p_ptr->congested &&
-                       p_ptr->wakeup;
+               wakeable = tipc_port_congested(p_ptr) && p_ptr->congested;
                p_ptr->acked += msg_msgcnt(msg);
                if (!tipc_port_congested(p_ptr)) {
                        p_ptr->congested = 0;
                        if (wakeable)
-                               p_ptr->wakeup(p_ptr);
+                               tipc_port_wakeup(p_ptr);
                }
                break;
        case CONN_PROBE:
@@ -585,8 +504,8 @@ static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id)
                ret = tipc_snprintf(buf, len, "%-10u:", p_ptr->ref);
 
        if (p_ptr->connected) {
-               u32 dport = port_peerport(p_ptr);
-               u32 destnode = port_peernode(p_ptr);
+               u32 dport = tipc_port_peerport(p_ptr);
+               u32 destnode = tipc_port_peernode(p_ptr);
 
                ret += tipc_snprintf(buf + ret, len - ret,
                                     " connected to <%u.%u.%u:%u>",
@@ -674,34 +593,6 @@ void tipc_acknowledge(u32 ref, u32 ack)
        tipc_net_route_msg(buf);
 }
 
-int tipc_portimportance(u32 ref, unsigned int *importance)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       *importance = (unsigned int)msg_importance(&p_ptr->phdr);
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-int tipc_set_portimportance(u32 ref, unsigned int imp)
-{
-       struct tipc_port *p_ptr;
-
-       if (imp > TIPC_CRITICAL_IMPORTANCE)
-               return -EINVAL;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       msg_set_importance(&p_ptr->phdr, (u32)imp);
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-
 int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
                 struct tipc_name_seq const *seq)
 {
@@ -883,7 +774,7 @@ int tipc_port_rcv(struct sk_buff *buf)
        /* validate destination & pass to port, otherwise reject message */
        p_ptr = tipc_port_lock(destport);
        if (likely(p_ptr)) {
-               err = p_ptr->dispatcher(p_ptr, buf);
+               err = tipc_sk_rcv(&tipc_port_to_sock(p_ptr)->sk, buf);
                tipc_port_unlock(p_ptr);
                if (likely(!err))
                        return dsz;
@@ -914,19 +805,19 @@ static int tipc_port_iovec_rcv(struct tipc_port *sender,
 /**
  * tipc_send - send message sections on connection
  */
-int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
+int tipc_send(struct tipc_port *p_ptr,
+             struct iovec const *msg_sect,
+             unsigned int len)
 {
-       struct tipc_port *p_ptr;
        u32 destnode;
        int res;
 
-       p_ptr = tipc_port_deref(ref);
-       if (!p_ptr || !p_ptr->connected)
+       if (!p_ptr->connected)
                return -EINVAL;
 
        p_ptr->congested = 1;
        if (!tipc_port_congested(p_ptr)) {
-               destnode = port_peernode(p_ptr);
+               destnode = tipc_port_peernode(p_ptr);
                if (likely(!in_own_node(destnode)))
                        res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len,
                                                        destnode);
@@ -940,7 +831,7 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
                        return res;
                }
        }
-       if (port_unreliable(p_ptr)) {
+       if (tipc_port_unreliable(p_ptr)) {
                p_ptr->congested = 0;
                return len;
        }
@@ -950,17 +841,18 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
 /**
  * tipc_send2name - send message sections to port name
  */
-int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
-                  struct iovec const *msg_sect, unsigned int len)
+int tipc_send2name(struct tipc_port *p_ptr,
+                  struct tipc_name const *name,
+                  unsigned int domain,
+                  struct iovec const *msg_sect,
+                  unsigned int len)
 {
-       struct tipc_port *p_ptr;
        struct tipc_msg *msg;
        u32 destnode = domain;
        u32 destport;
        int res;
 
-       p_ptr = tipc_port_deref(ref);
-       if (!p_ptr || p_ptr->connected)
+       if (p_ptr->connected)
                return -EINVAL;
 
        msg = &p_ptr->phdr;
@@ -987,9 +879,9 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
                                p_ptr->sent++;
                        return res;
                }
-               if (port_unreliable(p_ptr)) {
+               if (tipc_port_unreliable(p_ptr))
                        return len;
-               }
+
                return -ELINKCONG;
        }
        return tipc_port_iovec_reject(p_ptr, msg, msg_sect, len,
@@ -999,15 +891,15 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
 /**
  * tipc_send2port - send message sections to port identity
  */
-int tipc_send2port(u32 ref, struct tipc_portid const *dest,
-                  struct iovec const *msg_sect, unsigned int len)
+int tipc_send2port(struct tipc_port *p_ptr,
+                  struct tipc_portid const *dest,
+                  struct iovec const *msg_sect,
+                  unsigned int len)
 {
-       struct tipc_port *p_ptr;
        struct tipc_msg *msg;
        int res;
 
-       p_ptr = tipc_port_deref(ref);
-       if (!p_ptr || p_ptr->connected)
+       if (p_ptr->connected)
                return -EINVAL;
 
        msg = &p_ptr->phdr;
@@ -1030,8 +922,8 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest,
                        p_ptr->sent++;
                return res;
        }
-       if (port_unreliable(p_ptr)) {
+       if (tipc_port_unreliable(p_ptr))
                return len;
-       }
+
        return -ELINKCONG;
 }
index 3ec3e94e43349ac316aa1f6108e8abbb2e79304d..a00397393bd1d9179bd779339500e34bd710aa5b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/port.h: Include file for TIPC port code
  *
- * Copyright (c) 1994-2007, Ericsson AB
+ * Copyright (c) 1994-2007, 2014, Ericsson AB
  * Copyright (c) 2004-2007, 2010-2013, Wind River Systems
  * All rights reserved.
  *
@@ -48,7 +48,6 @@
 
 /**
  * struct tipc_port - TIPC port structure
- * @sk: pointer to socket handle
  * @lock: pointer to spinlock for controlling access to port
  * @connected: non-zero if port is currently connected to a peer port
  * @conn_type: TIPC type used when connection was established
@@ -60,8 +59,6 @@
  * @ref: unique reference to port in TIPC object registry
  * @phdr: preformatted message header used when sending messages
  * @port_list: adjacent ports in TIPC's global list of ports
- * @dispatcher: ptr to routine which handles received messages
- * @wakeup: ptr to routine to call when port is no longer congested
  * @wait_list: adjacent ports in list of ports waiting on link congestion
  * @waiting_pkts:
  * @sent: # of non-empty messages sent by port
@@ -74,7 +71,6 @@
  * @subscription: "node down" subscription used to terminate failed connections
  */
 struct tipc_port {
-       struct sock *sk;
        spinlock_t *lock;
        int connected;
        u32 conn_type;
@@ -86,8 +82,6 @@ struct tipc_port {
        u32 ref;
        struct tipc_msg phdr;
        struct list_head port_list;
-       u32 (*dispatcher)(struct tipc_port *, struct sk_buff *);
-       void (*wakeup)(struct tipc_port *);
        struct list_head wait_list;
        u32 waiting_pkts;
        u32 sent;
@@ -106,29 +100,18 @@ struct tipc_port_list;
 /*
  * TIPC port manipulation routines
  */
-struct tipc_port *tipc_createport(struct sock *sk,
-                                 u32 (*dispatcher)(struct tipc_port *,
-                                 struct sk_buff *),
-                                 void (*wakeup)(struct tipc_port *),
-                                 const u32 importance);
+u32 tipc_port_init(struct tipc_port *p_ptr,
+                  const unsigned int importance);
 
 int tipc_reject_msg(struct sk_buff *buf, u32 err);
 
 void tipc_acknowledge(u32 port_ref, u32 ack);
 
-int tipc_deleteport(struct tipc_port *p_ptr);
-
-int tipc_portimportance(u32 portref, unsigned int *importance);
-int tipc_set_portimportance(u32 portref, unsigned int importance);
-
-int tipc_portunreliable(u32 portref, unsigned int *isunreliable);
-int tipc_set_portunreliable(u32 portref, unsigned int isunreliable);
-
-int tipc_portunreturnable(u32 portref, unsigned int *isunreturnable);
-int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable);
+void tipc_port_destroy(struct tipc_port *p_ptr);
 
 int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
                 struct tipc_name_seq const *name_seq);
+
 int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope,
                  struct tipc_name_seq const *name_seq);
 
@@ -138,6 +121,7 @@ int tipc_port_disconnect(u32 portref);
 
 int tipc_port_shutdown(u32 ref);
 
+void tipc_port_wakeup(struct tipc_port *port);
 
 /*
  * The following routines require that the port be locked on entry
@@ -151,20 +135,33 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg);
  * TIPC messaging routines
  */
 int tipc_port_rcv(struct sk_buff *buf);
-int tipc_send(u32 portref, struct iovec const *msg_sect, unsigned int len);
-
-int tipc_send2name(u32 portref, struct tipc_name const *name, u32 domain,
-                  struct iovec const *msg_sect, unsigned int len);
 
-int tipc_send2port(u32 portref, struct tipc_portid const *dest,
-                  struct iovec const *msg_sect, unsigned int len);
-
-int tipc_port_mcast_xmit(u32 portref, struct tipc_name_seq const *seq,
-                        struct iovec const *msg, unsigned int len);
-
-int tipc_port_iovec_reject(struct tipc_port *p_ptr, struct tipc_msg *hdr,
-                          struct iovec const *msg_sect, unsigned int len,
+int tipc_send(struct tipc_port *port,
+             struct iovec const *msg_sect,
+             unsigned int len);
+
+int tipc_send2name(struct tipc_port *port,
+                  struct tipc_name const *name,
+                  u32 domain,
+                  struct iovec const *msg_sect,
+                  unsigned int len);
+
+int tipc_send2port(struct tipc_port *port,
+                  struct tipc_portid const *dest,
+                  struct iovec const *msg_sect,
+                  unsigned int len);
+
+int tipc_port_mcast_xmit(struct tipc_port *port,
+                        struct tipc_name_seq const *seq,
+                        struct iovec const *msg,
+                        unsigned int len);
+
+int tipc_port_iovec_reject(struct tipc_port *p_ptr,
+                          struct tipc_msg *hdr,
+                          struct iovec const *msg_sect,
+                          unsigned int len,
                           int err);
+
 struct sk_buff *tipc_port_get_ports(void);
 void tipc_port_proto_rcv(struct sk_buff *buf);
 void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp);
@@ -188,14 +185,53 @@ static inline void tipc_port_unlock(struct tipc_port *p_ptr)
        spin_unlock_bh(p_ptr->lock);
 }
 
-static inline struct tipc_port *tipc_port_deref(u32 ref)
+static inline int tipc_port_congested(struct tipc_port *p_ptr)
+{
+       return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2);
+}
+
+
+static inline u32 tipc_port_peernode(struct tipc_port *p_ptr)
 {
-       return (struct tipc_port *)tipc_ref_deref(ref);
+       return msg_destnode(&p_ptr->phdr);
 }
 
-static inline int tipc_port_congested(struct tipc_port *p_ptr)
+static inline u32 tipc_port_peerport(struct tipc_port *p_ptr)
 {
-       return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2);
+       return msg_destport(&p_ptr->phdr);
+}
+
+static inline  bool tipc_port_unreliable(struct tipc_port *port)
+{
+       return msg_src_droppable(&port->phdr) != 0;
+}
+
+static inline void tipc_port_set_unreliable(struct tipc_port *port,
+                                           bool unreliable)
+{
+       msg_set_src_droppable(&port->phdr, unreliable ? 1 : 0);
+}
+
+static inline bool tipc_port_unreturnable(struct tipc_port *port)
+{
+       return msg_dest_droppable(&port->phdr) != 0;
+}
+
+static inline void tipc_port_set_unreturnable(struct tipc_port *port,
+                                            bool unreturnable)
+{
+       msg_set_dest_droppable(&port->phdr, unreturnable ? 1 : 0);
+}
+
+
+static inline int tipc_port_importance(struct tipc_port *port)
+{
+       return msg_importance(&port->phdr);
+}
+
+static inline void tipc_port_set_importance(struct tipc_port *port, int imp)
+{
+       msg_set_importance(&port->phdr, (u32)imp);
 }
 
 #endif
index 2a2a938dc22cb3c14def50169afffa37ea5bec86..3d4ecd754eeef578e708e8219d8dc636093ccdfe 100644 (file)
@@ -89,7 +89,7 @@ struct ref_table {
 
 static struct ref_table tipc_ref_table;
 
-static DEFINE_RWLOCK(ref_table_lock);
+static DEFINE_SPINLOCK(ref_table_lock);
 
 /**
  * tipc_ref_table_init - create reference table for objects
@@ -126,9 +126,6 @@ int tipc_ref_table_init(u32 requested_size, u32 start)
  */
 void tipc_ref_table_stop(void)
 {
-       if (!tipc_ref_table.entries)
-               return;
-
        vfree(tipc_ref_table.entries);
        tipc_ref_table.entries = NULL;
 }
@@ -162,7 +159,7 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
        }
 
        /* take a free entry, if available; otherwise initialize a new entry */
-       write_lock_bh(&ref_table_lock);
+       spin_lock_bh(&ref_table_lock);
        if (tipc_ref_table.first_free) {
                index = tipc_ref_table.first_free;
                entry = &(tipc_ref_table.entries[index]);
@@ -178,7 +175,7 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
        } else {
                ref = 0;
        }
-       write_unlock_bh(&ref_table_lock);
+       spin_unlock_bh(&ref_table_lock);
 
        /*
         * Grab the lock so no one else can modify this entry
@@ -219,7 +216,7 @@ void tipc_ref_discard(u32 ref)
        index = ref & index_mask;
        entry = &(tipc_ref_table.entries[index]);
 
-       write_lock_bh(&ref_table_lock);
+       spin_lock_bh(&ref_table_lock);
 
        if (!entry->object) {
                pr_err("Attempt to discard ref. to non-existent obj\n");
@@ -245,7 +242,7 @@ void tipc_ref_discard(u32 ref)
        tipc_ref_table.last_free = index;
 
 exit:
-       write_unlock_bh(&ref_table_lock);
+       spin_unlock_bh(&ref_table_lock);
 }
 
 /**
@@ -267,20 +264,3 @@ void *tipc_ref_lock(u32 ref)
        }
        return NULL;
 }
-
-
-/**
- * tipc_ref_deref - return pointer referenced object (without locking it)
- */
-void *tipc_ref_deref(u32 ref)
-{
-       if (likely(tipc_ref_table.entries)) {
-               struct reference *entry;
-
-               entry = &tipc_ref_table.entries[ref &
-                                               tipc_ref_table.index_mask];
-               if (likely(entry->ref == ref))
-                       return entry->object;
-       }
-       return NULL;
-}
index 5bc8e7ab84de8192ca71c97a0ae415474f8e266c..d01aa1df63b86e391ed61a2fb2b31ff245fdc87e 100644 (file)
@@ -44,6 +44,5 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock);
 void tipc_ref_discard(u32 ref);
 
 void *tipc_ref_lock(u32 ref);
-void *tipc_ref_deref(u32 ref);
 
 #endif
index b635ca347a870dc55187c221b3df1f2dc295a333..646a930eefbf8fa9a86cfe7011848143aafa49b8 100644 (file)
@@ -87,7 +87,6 @@ static void tipc_clean_outqueues(struct tipc_conn *con);
 static void tipc_conn_kref_release(struct kref *kref)
 {
        struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
-       struct tipc_server *s = con->server;
 
        if (con->sock) {
                tipc_sock_release_local(con->sock);
@@ -95,10 +94,6 @@ static void tipc_conn_kref_release(struct kref *kref)
        }
 
        tipc_clean_outqueues(con);
-
-       if (con->conid)
-               s->tipc_conn_shutdown(con->conid, con->usr_data);
-
        kfree(con);
 }
 
@@ -181,6 +176,9 @@ static void tipc_close_conn(struct tipc_conn *con)
        struct tipc_server *s = con->server;
 
        if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
+               if (con->conid)
+                       s->tipc_conn_shutdown(con->conid, con->usr_data);
+
                spin_lock_bh(&s->idr_lock);
                idr_remove(&s->conn_idr, con->conid);
                s->idr_in_use--;
@@ -429,10 +427,12 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid,
        list_add_tail(&e->list, &con->outqueue);
        spin_unlock_bh(&con->outqueue_lock);
 
-       if (test_bit(CF_CONNECTED, &con->flags))
+       if (test_bit(CF_CONNECTED, &con->flags)) {
                if (!queue_work(s->send_wq, &con->swork))
                        conn_put(con);
-
+       } else {
+               conn_put(con);
+       }
        return 0;
 }
 
@@ -573,7 +573,6 @@ int tipc_server_start(struct tipc_server *s)
                kmem_cache_destroy(s->rcvbuf_cache);
                return ret;
        }
-       s->enabled = 1;
        return ret;
 }
 
@@ -583,10 +582,6 @@ void tipc_server_stop(struct tipc_server *s)
        int total = 0;
        int id;
 
-       if (!s->enabled)
-               return;
-
-       s->enabled = 0;
        spin_lock_bh(&s->idr_lock);
        for (id = 0; total < s->idr_in_use; id++) {
                con = idr_find(&s->conn_idr, id);
index 98b23f20bc0f5cbb1631111177bd0d88adfcaa68..be817b0b547e87148a103284adc5285a66147c28 100644 (file)
@@ -56,7 +56,6 @@
  * @name: server name
  * @imp: message importance
  * @type: socket type
- * @enabled: identify whether server is launched or not
  */
 struct tipc_server {
        struct idr conn_idr;
@@ -74,7 +73,6 @@ struct tipc_server {
        const char name[TIPC_SERVER_NAME_LEN];
        int imp;
        int type;
-       int enabled;
 };
 
 int tipc_conn_sendmsg(struct tipc_server *s, int conid,
index fb885977bd2a534e87006bb47f7db546508cbc1a..29b7f26a12cf6b29c0bac4c65354385fad036391 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/socket.c: TIPC socket API
  *
- * Copyright (c) 2001-2007, 2012 Ericsson AB
+ * Copyright (c) 2001-2007, 2012-2014, Ericsson AB
  * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
  * All rights reserved.
  *
 #include "port.h"
 
 #include <linux/export.h>
-#include <net/sock.h>
 
 #define SS_LISTENING   -1      /* socket is listening */
 #define SS_READY       -2      /* socket is connectionless */
 
 #define CONN_TIMEOUT_DEFAULT   8000    /* default connect timeout = 8s */
 
-struct tipc_sock {
-       struct sock sk;
-       struct tipc_port *p;
-       struct tipc_portid peer_name;
-       unsigned int conn_timeout;
-};
-
-#define tipc_sk(sk) ((struct tipc_sock *)(sk))
-#define tipc_sk_port(sk) (tipc_sk(sk)->p)
-
 static int backlog_rcv(struct sock *sk, struct sk_buff *skb);
-static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf);
-static void wakeupdispatch(struct tipc_port *tport);
 static void tipc_data_ready(struct sock *sk, int len);
 static void tipc_write_space(struct sock *sk);
 static int tipc_release(struct socket *sock);
@@ -70,8 +57,6 @@ static const struct proto_ops msg_ops;
 static struct proto tipc_proto;
 static struct proto tipc_proto_kern;
 
-static int sockets_enabled;
-
 /*
  * Revised TIPC socket locking policy:
  *
@@ -117,6 +102,8 @@ static int sockets_enabled;
  *   - port reference
  */
 
+#include "socket.h"
+
 /**
  * advance_rx_queue - discard first buffer in socket receive queue
  *
@@ -152,13 +139,15 @@ static void reject_rx_queue(struct sock *sk)
  *
  * Returns 0 on success, errno otherwise
  */
-static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,
-                         int kern)
+static int tipc_sk_create(struct net *net, struct socket *sock,
+                         int protocol, int kern)
 {
        const struct proto_ops *ops;
        socket_state state;
        struct sock *sk;
-       struct tipc_port *tp_ptr;
+       struct tipc_sock *tsk;
+       struct tipc_port *port;
+       u32 ref;
 
        /* Validate arguments */
        if (unlikely(protocol != 0))
@@ -191,10 +180,12 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,
        if (sk == NULL)
                return -ENOMEM;
 
-       /* Allocate TIPC port for socket to use */
-       tp_ptr = tipc_createport(sk, &dispatch, &wakeupdispatch,
-                                TIPC_LOW_IMPORTANCE);
-       if (unlikely(!tp_ptr)) {
+       tsk = tipc_sk(sk);
+       port = &tsk->port;
+
+       ref = tipc_port_init(port, TIPC_LOW_IMPORTANCE);
+       if (!ref) {
+               pr_warn("Socket registration failed, ref. table exhausted\n");
                sk_free(sk);
                return -ENOMEM;
        }
@@ -208,17 +199,14 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,
        sk->sk_rcvbuf = sysctl_tipc_rmem[1];
        sk->sk_data_ready = tipc_data_ready;
        sk->sk_write_space = tipc_write_space;
-       tipc_sk(sk)->p = tp_ptr;
        tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT;
-
-       spin_unlock_bh(tp_ptr->lock);
+       tipc_port_unlock(port);
 
        if (sock->state == SS_READY) {
-               tipc_set_portunreturnable(tp_ptr->ref, 1);
+               tipc_port_set_unreturnable(port, true);
                if (sock->type == SOCK_DGRAM)
-                       tipc_set_portunreliable(tp_ptr->ref, 1);
+                       tipc_port_set_unreliable(port, true);
        }
-
        return 0;
 }
 
@@ -310,7 +298,8 @@ int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
 static int tipc_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport;
+       struct tipc_sock *tsk;
+       struct tipc_port *port;
        struct sk_buff *buf;
        int res;
 
@@ -321,7 +310,8 @@ static int tipc_release(struct socket *sock)
        if (sk == NULL)
                return 0;
 
-       tport = tipc_sk_port(sk);
+       tsk = tipc_sk(sk);
+       port = &tsk->port;
        lock_sock(sk);
 
        /*
@@ -338,17 +328,16 @@ static int tipc_release(struct socket *sock)
                        if ((sock->state == SS_CONNECTING) ||
                            (sock->state == SS_CONNECTED)) {
                                sock->state = SS_DISCONNECTING;
-                               tipc_port_disconnect(tport->ref);
+                               tipc_port_disconnect(port->ref);
                        }
                        tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
                }
        }
 
-       /*
-        * Delete TIPC port; this ensures no more messages are queued
-        * (also disconnects an active connection & sends a 'FIN-' to peer)
+       /* Destroy TIPC port; also disconnects an active connection and
+        * sends a 'FIN-' to peer.
         */
-       res = tipc_deleteport(tport);
+       tipc_port_destroy(port);
 
        /* Discard any remaining (connection-based) messages in receive queue */
        __skb_queue_purge(&sk->sk_receive_queue);
@@ -383,12 +372,12 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
 {
        struct sock *sk = sock->sk;
        struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
-       struct tipc_port *tport = tipc_sk_port(sock->sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
        int res = -EINVAL;
 
        lock_sock(sk);
        if (unlikely(!uaddr_len)) {
-               res = tipc_withdraw(tport, 0, NULL);
+               res = tipc_withdraw(&tsk->port, 0, NULL);
                goto exit;
        }
 
@@ -416,8 +405,8 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
        }
 
        res = (addr->scope > 0) ?
-               tipc_publish(tport, addr->scope, &addr->addr.nameseq) :
-               tipc_withdraw(tport, -addr->scope, &addr->addr.nameseq);
+               tipc_publish(&tsk->port, addr->scope, &addr->addr.nameseq) :
+               tipc_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq);
 exit:
        release_sock(sk);
        return res;
@@ -440,17 +429,17 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,
                        int *uaddr_len, int peer)
 {
        struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
-       struct tipc_sock *tsock = tipc_sk(sock->sk);
+       struct tipc_sock *tsk = tipc_sk(sock->sk);
 
        memset(addr, 0, sizeof(*addr));
        if (peer) {
                if ((sock->state != SS_CONNECTED) &&
                        ((peer != 2) || (sock->state != SS_DISCONNECTING)))
                        return -ENOTCONN;
-               addr->addr.id.ref = tsock->peer_name.ref;
-               addr->addr.id.node = tsock->peer_name.node;
+               addr->addr.id.ref = tipc_port_peerport(&tsk->port);
+               addr->addr.id.node = tipc_port_peernode(&tsk->port);
        } else {
-               addr->addr.id.ref = tsock->p->ref;
+               addr->addr.id.ref = tsk->port.ref;
                addr->addr.id.node = tipc_own_addr;
        }
 
@@ -507,18 +496,19 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
                              poll_table *wait)
 {
        struct sock *sk = sock->sk;
+       struct tipc_sock *tsk = tipc_sk(sk);
        u32 mask = 0;
 
        sock_poll_wait(file, sk_sleep(sk), wait);
 
        switch ((int)sock->state) {
        case SS_UNCONNECTED:
-               if (!tipc_sk_port(sk)->congested)
+               if (!tsk->port.congested)
                        mask |= POLLOUT;
                break;
        case SS_READY:
        case SS_CONNECTED:
-               if (!tipc_sk_port(sk)->congested)
+               if (!tsk->port.congested)
                        mask |= POLLOUT;
                /* fall thru' */
        case SS_CONNECTING:
@@ -568,7 +558,7 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
 static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
        DEFINE_WAIT(wait);
        int done;
 
@@ -584,12 +574,13 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)
                        return sock_intr_errno(*timeo_p);
 
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-               done = sk_wait_event(sk, timeo_p, !tport->congested);
+               done = sk_wait_event(sk, timeo_p, !tsk->port.congested);
                finish_wait(sk_sleep(sk), &wait);
        } while (!done);
        return 0;
 }
 
+
 /**
  * tipc_sendmsg - send message in connectionless manner
  * @iocb: if NULL, indicates that socket lock is already held
@@ -608,7 +599,8 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
                        struct msghdr *m, size_t total_len)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
        int needs_conn;
        long timeo;
@@ -635,13 +627,13 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
                        res = -EISCONN;
                        goto exit;
                }
-               if (tport->published) {
+               if (tsk->port.published) {
                        res = -EOPNOTSUPP;
                        goto exit;
                }
                if (dest->addrtype == TIPC_ADDR_NAME) {
-                       tport->conn_type = dest->addr.name.name.type;
-                       tport->conn_instance = dest->addr.name.name.instance;
+                       tsk->port.conn_type = dest->addr.name.name.type;
+                       tsk->port.conn_instance = dest->addr.name.name.instance;
                }
 
                /* Abort any pending connection attempts (very unlikely) */
@@ -654,13 +646,13 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
                        res = dest_name_check(dest, m);
                        if (res)
                                break;
-                       res = tipc_send2name(tport->ref,
+                       res = tipc_send2name(port,
                                             &dest->addr.name.name,
                                             dest->addr.name.domain,
                                             m->msg_iov,
                                             total_len);
                } else if (dest->addrtype == TIPC_ADDR_ID) {
-                       res = tipc_send2port(tport->ref,
+                       res = tipc_send2port(port,
                                             &dest->addr.id,
                                             m->msg_iov,
                                             total_len);
@@ -672,7 +664,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
                        res = dest_name_check(dest, m);
                        if (res)
                                break;
-                       res = tipc_port_mcast_xmit(tport->ref,
+                       res = tipc_port_mcast_xmit(port,
                                                   &dest->addr.nameseq,
                                                   m->msg_iov,
                                                   total_len);
@@ -696,7 +688,8 @@ exit:
 static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        DEFINE_WAIT(wait);
        int done;
 
@@ -715,7 +708,7 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p)
 
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                done = sk_wait_event(sk, timeo_p,
-                                    (!tport->congested || !tport->connected));
+                                    (!port->congested || !port->connected));
                finish_wait(sk_sleep(sk), &wait);
        } while (!done);
        return 0;
@@ -736,7 +729,7 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock,
                            struct msghdr *m, size_t total_len)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
        int res = -EINVAL;
        long timeo;
@@ -761,7 +754,7 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock,
 
        timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
        do {
-               res = tipc_send(tport->ref, m->msg_iov, total_len);
+               res = tipc_send(&tsk->port, m->msg_iov, total_len);
                if (likely(res != -ELINKCONG))
                        break;
                res = tipc_wait_for_sndpkt(sock, &timeo);
@@ -790,7 +783,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
                            struct msghdr *m, size_t total_len)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
        struct msghdr my_msg;
        struct iovec my_iov;
        struct iovec *curr_iov;
@@ -838,14 +831,14 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
        my_msg.msg_name = NULL;
        bytes_sent = 0;
 
-       hdr_size = msg_hdr_sz(&tport->phdr);
+       hdr_size = msg_hdr_sz(&tsk->port.phdr);
 
        while (curr_iovlen--) {
                curr_start = curr_iov->iov_base;
                curr_left = curr_iov->iov_len;
 
                while (curr_left) {
-                       bytes_to_send = tport->max_pkt - hdr_size;
+                       bytes_to_send = tsk->port.max_pkt - hdr_size;
                        if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE)
                                bytes_to_send = TIPC_MAX_USER_MSG_SIZE;
                        if (curr_left < bytes_to_send)
@@ -874,27 +867,25 @@ exit:
 
 /**
  * auto_connect - complete connection setup to a remote port
- * @sock: socket structure
+ * @tsk: tipc socket structure
  * @msg: peer's response message
  *
  * Returns 0 on success, errno otherwise
  */
-static int auto_connect(struct socket *sock, struct tipc_msg *msg)
+static int auto_connect(struct tipc_sock *tsk, struct tipc_msg *msg)
 {
-       struct tipc_sock *tsock = tipc_sk(sock->sk);
-       struct tipc_port *p_ptr;
+       struct tipc_port *port = &tsk->port;
+       struct socket *sock = tsk->sk.sk_socket;
+       struct tipc_portid peer;
 
-       tsock->peer_name.ref = msg_origport(msg);
-       tsock->peer_name.node = msg_orignode(msg);
-       p_ptr = tipc_port_deref(tsock->p->ref);
-       if (!p_ptr)
-               return -EINVAL;
+       peer.ref = msg_origport(msg);
+       peer.node = msg_orignode(msg);
 
-       __tipc_port_connect(tsock->p->ref, p_ptr, &tsock->peer_name);
+       __tipc_port_connect(port->ref, port, &peer);
 
        if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)
                return -EINVAL;
-       msg_set_importance(&p_ptr->phdr, (u32)msg_importance(msg));
+       msg_set_importance(&port->phdr, (u32)msg_importance(msg));
        sock->state = SS_CONNECTED;
        return 0;
 }
@@ -1001,7 +992,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo)
 
        for (;;) {
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-               if (skb_queue_empty(&sk->sk_receive_queue)) {
+               if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
                        if (sock->state == SS_DISCONNECTING) {
                                err = -ENOTCONN;
                                break;
@@ -1040,7 +1031,8 @@ static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock,
                        struct msghdr *m, size_t buf_len, int flags)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        struct tipc_msg *msg;
        long timeo;
@@ -1083,7 +1075,7 @@ restart:
        set_orig_addr(m, msg);
 
        /* Capture ancillary data (optional) */
-       res = anc_data_recv(m, msg, tport);
+       res = anc_data_recv(m, msg, port);
        if (res)
                goto exit;
 
@@ -1109,8 +1101,8 @@ restart:
        /* Consume received message (optional) */
        if (likely(!(flags & MSG_PEEK))) {
                if ((sock->state != SS_READY) &&
-                   (++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
-                       tipc_acknowledge(tport->ref, tport->conn_unacked);
+                   (++port->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
+                       tipc_acknowledge(port->ref, port->conn_unacked);
                advance_rx_queue(sk);
        }
 exit:
@@ -1134,7 +1126,8 @@ static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock,
                            struct msghdr *m, size_t buf_len, int flags)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        struct tipc_msg *msg;
        long timeo;
@@ -1179,7 +1172,7 @@ restart:
        /* Optionally capture sender's address & ancillary data of first msg */
        if (sz_copied == 0) {
                set_orig_addr(m, msg);
-               res = anc_data_recv(m, msg, tport);
+               res = anc_data_recv(m, msg, port);
                if (res)
                        goto exit;
        }
@@ -1217,8 +1210,8 @@ restart:
 
        /* Consume received message (optional) */
        if (likely(!(flags & MSG_PEEK))) {
-               if (unlikely(++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
-                       tipc_acknowledge(tport->ref, tport->conn_unacked);
+               if (unlikely(++port->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
+                       tipc_acknowledge(port->ref, port->conn_unacked);
                advance_rx_queue(sk);
        }
 
@@ -1270,17 +1263,19 @@ static void tipc_data_ready(struct sock *sk, int len)
 
 /**
  * filter_connect - Handle all incoming messages for a connection-based socket
- * @tsock: TIPC socket
+ * @tsk: TIPC socket
  * @msg: message
  *
  * Returns TIPC error status code and socket error status code
  * once it encounters some errors
  */
-static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
+static u32 filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
 {
-       struct socket *sock = tsock->sk.sk_socket;
+       struct sock *sk = &tsk->sk;
+       struct tipc_port *port = &tsk->port;
+       struct socket *sock = sk->sk_socket;
        struct tipc_msg *msg = buf_msg(*buf);
-       struct sock *sk = &tsock->sk;
+
        u32 retval = TIPC_ERR_NO_PORT;
        int res;
 
@@ -1290,10 +1285,10 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
        switch ((int)sock->state) {
        case SS_CONNECTED:
                /* Accept only connection-based messages sent by peer */
-               if (msg_connected(msg) && tipc_port_peer_msg(tsock->p, msg)) {
+               if (msg_connected(msg) && tipc_port_peer_msg(port, msg)) {
                        if (unlikely(msg_errcode(msg))) {
                                sock->state = SS_DISCONNECTING;
-                               __tipc_port_disconnect(tsock->p);
+                               __tipc_port_disconnect(port);
                        }
                        retval = TIPC_OK;
                }
@@ -1310,7 +1305,7 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
                if (unlikely(!msg_connected(msg)))
                        break;
 
-               res = auto_connect(sock, msg);
+               res = auto_connect(tsk, msg);
                if (res) {
                        sock->state = SS_DISCONNECTING;
                        sk->sk_err = -res;
@@ -1389,6 +1384,7 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf)
 static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
 {
        struct socket *sock = sk->sk_socket;
+       struct tipc_sock *tsk = tipc_sk(sk);
        struct tipc_msg *msg = buf_msg(buf);
        unsigned int limit = rcvbuf_limit(sk, buf);
        u32 res = TIPC_OK;
@@ -1401,7 +1397,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
                if (msg_connected(msg))
                        return TIPC_ERR_NO_PORT;
        } else {
-               res = filter_connect(tipc_sk(sk), &buf);
+               res = filter_connect(tsk, &buf);
                if (res != TIPC_OK || buf == NULL)
                        return res;
        }
@@ -1439,17 +1435,16 @@ static int backlog_rcv(struct sock *sk, struct sk_buff *buf)
 }
 
 /**
- * dispatch - handle incoming message
- * @tport: TIPC port that received message
+ * tipc_sk_rcv - handle incoming message
+ * @sk:  socket receiving message
  * @buf: message
  *
  * Called with port lock already taken.
  *
  * Returns TIPC error status code (TIPC_OK if message is not to be rejected)
  */
-static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
+u32 tipc_sk_rcv(struct sock *sk, struct sk_buff *buf)
 {
-       struct sock *sk = tport->sk;
        u32 res;
 
        /*
@@ -1472,19 +1467,6 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
        return res;
 }
 
-/**
- * wakeupdispatch - wake up port after congestion
- * @tport: port to wakeup
- *
- * Called with port lock already taken.
- */
-static void wakeupdispatch(struct tipc_port *tport)
-{
-       struct sock *sk = tport->sk;
-
-       sk->sk_write_space(sk);
-}
-
 static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)
 {
        struct sock *sk = sock->sk;
@@ -1627,7 +1609,7 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)
        for (;;) {
                prepare_to_wait_exclusive(sk_sleep(sk), &wait,
                                          TASK_INTERRUPTIBLE);
-               if (skb_queue_empty(&sk->sk_receive_queue)) {
+               if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
                        release_sock(sk);
                        timeo = schedule_timeout(timeo);
                        lock_sock(sk);
@@ -1661,9 +1643,9 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
 {
        struct sock *new_sk, *sk = sock->sk;
        struct sk_buff *buf;
-       struct tipc_sock *new_tsock;
-       struct tipc_port *new_tport;
+       struct tipc_port *new_port;
        struct tipc_msg *msg;
+       struct tipc_portid peer;
        u32 new_ref;
        long timeo;
        int res;
@@ -1674,7 +1656,6 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
                res = -EINVAL;
                goto exit;
        }
-
        timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
        res = tipc_wait_for_accept(sock, timeo);
        if (res)
@@ -1687,9 +1668,8 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
                goto exit;
 
        new_sk = new_sock->sk;
-       new_tsock = tipc_sk(new_sk);
-       new_tport = new_tsock->p;
-       new_ref = new_tport->ref;
+       new_port = &tipc_sk(new_sk)->port;
+       new_ref = new_port->ref;
        msg = buf_msg(buf);
 
        /* we lock on new_sk; but lockdep sees the lock on sk */
@@ -1702,15 +1682,15 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
        reject_rx_queue(new_sk);
 
        /* Connect new socket to it's peer */
-       new_tsock->peer_name.ref = msg_origport(msg);
-       new_tsock->peer_name.node = msg_orignode(msg);
-       tipc_port_connect(new_ref, &new_tsock->peer_name);
+       peer.ref = msg_origport(msg);
+       peer.node = msg_orignode(msg);
+       tipc_port_connect(new_ref, &peer);
        new_sock->state = SS_CONNECTED;
 
-       tipc_set_portimportance(new_ref, msg_importance(msg));
+       tipc_port_set_importance(new_port, msg_importance(msg));
        if (msg_named(msg)) {
-               new_tport->conn_type = msg_nametype(msg);
-               new_tport->conn_instance = msg_nameinst(msg);
+               new_port->conn_type = msg_nametype(msg);
+               new_port->conn_instance = msg_nameinst(msg);
        }
 
        /*
@@ -1728,7 +1708,6 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
                skb_set_owner_r(buf, new_sk);
        }
        release_sock(new_sk);
-
 exit:
        release_sock(sk);
        return res;
@@ -1746,7 +1725,8 @@ exit:
 static int tipc_shutdown(struct socket *sock, int how)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        int res;
 
@@ -1767,10 +1747,10 @@ restart:
                                kfree_skb(buf);
                                goto restart;
                        }
-                       tipc_port_disconnect(tport->ref);
+                       tipc_port_disconnect(port->ref);
                        tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN);
                } else {
-                       tipc_port_shutdown(tport->ref);
+                       tipc_port_shutdown(port->ref);
                }
 
                sock->state = SS_DISCONNECTING;
@@ -1812,7 +1792,8 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
                           char __user *ov, unsigned int ol)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        u32 value;
        int res;
 
@@ -1830,16 +1811,16 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
 
        switch (opt) {
        case TIPC_IMPORTANCE:
-               res = tipc_set_portimportance(tport->ref, value);
+               tipc_port_set_importance(port, value);
                break;
        case TIPC_SRC_DROPPABLE:
                if (sock->type != SOCK_STREAM)
-                       res = tipc_set_portunreliable(tport->ref, value);
+                       tipc_port_set_unreliable(port, value);
                else
                        res = -ENOPROTOOPT;
                break;
        case TIPC_DEST_DROPPABLE:
-               res = tipc_set_portunreturnable(tport->ref, value);
+               tipc_port_set_unreturnable(port, value);
                break;
        case TIPC_CONN_TIMEOUT:
                tipc_sk(sk)->conn_timeout = value;
@@ -1871,7 +1852,8 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt,
                           char __user *ov, int __user *ol)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        int len;
        u32 value;
        int res;
@@ -1888,13 +1870,13 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt,
 
        switch (opt) {
        case TIPC_IMPORTANCE:
-               res = tipc_portimportance(tport->ref, &value);
+               value = tipc_port_importance(port);
                break;
        case TIPC_SRC_DROPPABLE:
-               res = tipc_portunreliable(tport->ref, &value);
+               value = tipc_port_unreliable(port);
                break;
        case TIPC_DEST_DROPPABLE:
-               res = tipc_portunreturnable(tport->ref, &value);
+               value = tipc_port_unreturnable(port);
                break;
        case TIPC_CONN_TIMEOUT:
                value = tipc_sk(sk)->conn_timeout;
@@ -2029,8 +2011,6 @@ int tipc_socket_init(void)
                proto_unregister(&tipc_proto);
                goto out;
        }
-
-       sockets_enabled = 1;
  out:
        return res;
 }
@@ -2040,10 +2020,6 @@ int tipc_socket_init(void)
  */
 void tipc_socket_stop(void)
 {
-       if (!sockets_enabled)
-               return;
-
-       sockets_enabled = 0;
        sock_unregister(tipc_family_ops.family);
        proto_unregister(&tipc_proto);
 }
diff --git a/net/tipc/socket.h b/net/tipc/socket.h
new file mode 100644 (file)
index 0000000..74e5c7f
--- /dev/null
@@ -0,0 +1,72 @@
+/* net/tipc/socket.h: Include file for TIPC socket code
+ *
+ * Copyright (c) 2014, Ericsson AB
+ * 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 names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_SOCK_H
+#define _TIPC_SOCK_H
+
+#include "port.h"
+#include <net/sock.h>
+
+/**
+ * struct tipc_sock - TIPC socket structure
+ * @sk: socket - interacts with 'port' and with user via the socket API
+ * @port: port - interacts with 'sk' and with the rest of the TIPC stack
+ * @peer_name: the peer of the connection, if any
+ * @conn_timeout: the time we can wait for an unresponded setup request
+ */
+
+struct tipc_sock {
+       struct sock sk;
+       struct tipc_port port;
+       unsigned int conn_timeout;
+};
+
+static inline struct tipc_sock *tipc_sk(const struct sock *sk)
+{
+       return container_of(sk, struct tipc_sock, sk);
+}
+
+static inline struct tipc_sock *tipc_port_to_sock(const struct tipc_port *port)
+{
+       return container_of(port, struct tipc_sock, port);
+}
+
+static inline void tipc_sock_wakeup(struct tipc_sock *tsk)
+{
+       tsk->sk.sk_write_space(&tsk->sk);
+}
+
+u32 tipc_sk_rcv(struct sock *sk, struct sk_buff *buf);
+
+#endif
index 7cb0bd5b1176872dcd09ca830a8a01c5b1ec37c6..11c9ae00837d66808755f1b8bee0542f449db6a1 100644 (file)
@@ -96,20 +96,16 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower,
 {
        struct tipc_subscriber *subscriber = sub->subscriber;
        struct kvec msg_sect;
-       int ret;
 
        msg_sect.iov_base = (void *)&sub->evt;
        msg_sect.iov_len = sizeof(struct tipc_event);
-
        sub->evt.event = htohl(event, sub->swap);
        sub->evt.found_lower = htohl(found_lower, sub->swap);
        sub->evt.found_upper = htohl(found_upper, sub->swap);
        sub->evt.port.ref = htohl(port_ref, sub->swap);
        sub->evt.port.node = htohl(node, sub->swap);
-       ret = tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL,
-                               msg_sect.iov_base, msg_sect.iov_len);
-       if (ret < 0)
-               pr_err("Sending subscription event failed, no memory\n");
+       tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, msg_sect.iov_base,
+                         msg_sect.iov_len);
 }
 
 /**
@@ -153,14 +149,6 @@ static void subscr_timeout(struct tipc_subscription *sub)
        /* The spin lock per subscriber is used to protect its members */
        spin_lock_bh(&subscriber->lock);
 
-       /* Validate if the connection related to the subscriber is
-        * closed (in case subscriber is terminating)
-        */
-       if (subscriber->conid == 0) {
-               spin_unlock_bh(&subscriber->lock);
-               return;
-       }
-
        /* Validate timeout (in case subscription is being cancelled) */
        if (sub->timeout == TIPC_WAIT_FOREVER) {
                spin_unlock_bh(&subscriber->lock);
@@ -215,9 +203,6 @@ static void subscr_release(struct tipc_subscriber *subscriber)
 
        spin_lock_bh(&subscriber->lock);
 
-       /* Invalidate subscriber reference */
-       subscriber->conid = 0;
-
        /* Destroy any existing subscriptions for subscriber */
        list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
                                 subscription_list) {
index 29fc8bee97022f456f8b64b8ff6ff54a977962dd..ce6ec6c2f4de9b1eaaf34973f874e39eff408a79 100644 (file)
@@ -163,9 +163,8 @@ static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
 
 static inline unsigned int unix_hash_fold(__wsum n)
 {
-       unsigned int hash = (__force unsigned int)n;
+       unsigned int hash = (__force unsigned int)csum_fold(n);
 
-       hash ^= hash>>16;
        hash ^= hash>>8;
        return hash&(UNIX_HASH_SIZE-1);
 }
index 2d4268c5529d94c0b31575e94f364a0975123e7f..cd10c1985074298b00cd308da7ce4544da7474c3 100644 (file)
@@ -705,12 +705,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_WDS:
-               /* these interface types don't really have a channel */
-               return;
        case NL80211_IFTYPE_P2P_DEVICE:
-               if (wdev->wiphy->features &
-                               NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL)
-                       *chanmode = CHAN_MODE_EXCLUSIVE;
+               /* these interface types don't really have a channel */
                return;
        case NL80211_IFTYPE_UNSPECIFIED:
        case NUM_NL80211_IFTYPES:
index 76ae6a605abb3366ab757bda121606d1b4747f10..eb7f40821c092c1cac98b0296e917a75b23ac145 100644 (file)
@@ -788,8 +788,6 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
        default:
                break;
        }
-
-       wdev->beacon_interval = 0;
 }
 
 static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
index 9a8217d2a90882f872451833cabe30159a64953f..fdfd3f063a9bcad326377d4da0b2f6c5354c5cb5 100644 (file)
@@ -105,6 +105,8 @@ function parse_reg_rule()
                        flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
                } else if (flagarray[arg] == "NO-IR") {
                        flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
+               } else if (flagarray[arg] == "AUTO-BW") {
+                       flags = flags "\n\t\t\tNL80211_RRF_AUTO_BW | "
                }
 
        }
index 1470b90e438f4bf6306be3591fdf6d376676ec5f..349db9ddc0d13737eb84f874bc3b556b61b38026 100644 (file)
@@ -128,12 +128,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 #endif
        check_chan = params->chandef.chan;
        if (params->userspace_handles_dfs) {
-               /* use channel NULL to check for radar even if the current
-                * channel is not a radar channel - it might decide to change
-                * to DFS channel later.
+               /* Check for radar even if the current channel is not
+                * a radar channel - it might decide to change to DFS
+                * channel later.
                 */
                radar_detect_width = BIT(params->chandef.width);
-               check_chan = NULL;
        }
 
        err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
index d42a3fcb2f67ae0fb7a563f07ee74f96fa17fee7..5af5cc6b2c4c2406475a3063a69eef80cc14691f 100644 (file)
@@ -236,6 +236,12 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
                if (!netif_running(wdev->netdev))
                        return -ENETDOWN;
 
+               /* cfg80211_can_use_chan() calls
+                * cfg80211_can_use_iftype_chan() with no radar
+                * detection, so if we're trying to use a radar
+                * channel here, something is wrong.
+                */
+               WARN_ON_ONCE(chandef->chan->flags & IEEE80211_CHAN_RADAR);
                err = cfg80211_can_use_chan(rdev, wdev, chandef->chan,
                                            CHAN_MODE_SHARED);
                if (err)
index 8e6b6a2d35cb27984aaddb73cdbc462ef3e350f6..2c38b28a85b9b1d800caaf617be18f06517b63cd 100644 (file)
@@ -384,6 +384,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
                                   .len = IEEE80211_QOS_MAP_LEN_MAX },
        [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
        [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
+       [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
 };
 
 /* policy for the key attributes */
@@ -4627,6 +4628,8 @@ static int parse_reg_rule(struct nlattr *tb[],
                return -EINVAL;
        if (!tb[NL80211_ATTR_FREQ_RANGE_END])
                return -EINVAL;
+       if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+               return -EINVAL;
        if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
                return -EINVAL;
 
@@ -4636,9 +4639,8 @@ static int parse_reg_rule(struct nlattr *tb[],
                nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
        freq_range->end_freq_khz =
                nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
-       if (tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
-               freq_range->max_bandwidth_khz =
-                       nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
+       freq_range->max_bandwidth_khz =
+               nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
 
        power_rule->max_eirp =
                nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
@@ -5710,8 +5712,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
        }
 
-       if (info->attrs[NL80211_ATTR_IE]) {
-               request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+       if (ie_len) {
+               request->ie_len = ie_len;
                memcpy((void *)request->ie,
                       nla_data(info->attrs[NL80211_ATTR_IE]),
                       request->ie_len);
@@ -5911,17 +5913,22 @@ skip_beacons:
        if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
                return -EINVAL;
 
-       if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
-           dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO ||
-           dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC) {
+       switch (dev->ieee80211_ptr->iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_MESH_POINT:
                err = cfg80211_chandef_dfs_required(wdev->wiphy,
                                                    &params.chandef);
-               if (err < 0) {
+               if (err < 0)
                        return err;
-               } else if (err) {
+               if (err) {
                        radar_detect_width = BIT(params.chandef.width);
                        params.radar_required = true;
                }
+               break;
+       default:
+               break;
        }
 
        err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
@@ -7269,6 +7276,7 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
        u8 action_code, dialog_token;
+       u32 peer_capability = 0;
        u16 status_code;
        u8 *peer;
 
@@ -7287,9 +7295,12 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
        action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
        status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
        dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
+       if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY])
+               peer_capability =
+                       nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]);
 
        return rdev_tdls_mgmt(rdev, dev, peer, action_code,
-                             dialog_token, status_code,
+                             dialog_token, status_code, peer_capability,
                              nla_data(info->attrs[NL80211_ATTR_IE]),
                              nla_len(info->attrs[NL80211_ATTR_IE]));
 }
index c8e225947adb2601d31dbb0f4a1aa5a4392d8bc5..74d97d33c938e8250ef300c2c3fb82d2a39b63b6 100644 (file)
@@ -769,13 +769,16 @@ static inline int rdev_set_rekey_data(struct cfg80211_registered_device *rdev,
 static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev,
                                 struct net_device *dev, u8 *peer,
                                 u8 action_code, u8 dialog_token,
-                                u16 status_code, const u8 *buf, size_t len)
+                                u16 status_code, u32 peer_capability,
+                                const u8 *buf, size_t len)
 {
        int ret;
        trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
-                            dialog_token, status_code, buf, len);
+                            dialog_token, status_code, peer_capability,
+                            buf, len);
        ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
-                                  dialog_token, status_code, buf, len);
+                                  dialog_token, status_code, peer_capability,
+                                  buf, len);
        trace_rdev_return_int(&rdev->wiphy, ret);
        return ret;
 }
index 27c5253e7a610b706ac99402727eda9bc66de755..90b82e08ae699b31bd405a495375a88dd5dd1af3 100644 (file)
@@ -563,9 +563,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
                if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz)
                        break;
 
-               if (freq_range_tmp->max_bandwidth_khz)
-                       break;
-
                freq_range = freq_range_tmp;
        }
 
@@ -582,9 +579,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
                if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz)
                        break;
 
-               if (freq_range_tmp->max_bandwidth_khz)
-                       break;
-
                freq_range = freq_range_tmp;
        }
 
@@ -729,21 +723,29 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
        max_bandwidth1 = freq_range1->max_bandwidth_khz;
        max_bandwidth2 = freq_range2->max_bandwidth_khz;
 
-       /*
-        * In case max_bandwidth1 == 0 and max_bandwith2 == 0 set
-        * output bandwidth as 0 (auto calculation). Next we will
-        * calculate this correctly in handle_channel function.
-        * In other case calculate output bandwidth here.
-        */
-       if (max_bandwidth1 || max_bandwidth2) {
-               if (!max_bandwidth1)
-                       max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1);
-               if (!max_bandwidth2)
-                       max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2);
-       }
+       if (rule1->flags & NL80211_RRF_AUTO_BW)
+               max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1);
+       if (rule2->flags & NL80211_RRF_AUTO_BW)
+               max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2);
 
        freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2);
 
+       intersected_rule->flags = rule1->flags | rule2->flags;
+
+       /*
+        * In case NL80211_RRF_AUTO_BW requested for both rules
+        * set AUTO_BW in intersected rule also. Next we will
+        * calculate BW correctly in handle_channel function.
+        * In other case remove AUTO_BW flag while we calculate
+        * maximum bandwidth correctly and auto calculation is
+        * not required.
+        */
+       if ((rule1->flags & NL80211_RRF_AUTO_BW) &&
+           (rule2->flags & NL80211_RRF_AUTO_BW))
+               intersected_rule->flags |= NL80211_RRF_AUTO_BW;
+       else
+               intersected_rule->flags &= ~NL80211_RRF_AUTO_BW;
+
        freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
        if (freq_range->max_bandwidth_khz > freq_diff)
                freq_range->max_bandwidth_khz = freq_diff;
@@ -753,8 +755,6 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
        power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
                power_rule2->max_antenna_gain);
 
-       intersected_rule->flags = rule1->flags | rule2->flags;
-
        if (!is_valid_reg_rule(intersected_rule))
                return -EINVAL;
 
@@ -938,31 +938,42 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
 EXPORT_SYMBOL(reg_initiator_name);
 
 #ifdef CONFIG_CFG80211_REG_DEBUG
-static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
+static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
+                                   struct ieee80211_channel *chan,
                                    const struct ieee80211_reg_rule *reg_rule)
 {
        const struct ieee80211_power_rule *power_rule;
        const struct ieee80211_freq_range *freq_range;
-       char max_antenna_gain[32];
+       char max_antenna_gain[32], bw[32];
 
        power_rule = &reg_rule->power_rule;
        freq_range = &reg_rule->freq_range;
 
        if (!power_rule->max_antenna_gain)
-               snprintf(max_antenna_gain, 32, "N/A");
+               snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A");
+       else
+               snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d",
+                        power_rule->max_antenna_gain);
+
+       if (reg_rule->flags & NL80211_RRF_AUTO_BW)
+               snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO",
+                        freq_range->max_bandwidth_khz,
+                        reg_get_max_bandwidth(regd, reg_rule));
        else
-               snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain);
+               snprintf(bw, sizeof(bw), "%d KHz",
+                        freq_range->max_bandwidth_khz);
 
        REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n",
                      chan->center_freq);
 
-       REG_DBG_PRINT("%d KHz - %d KHz @ %d KHz), (%s mBi, %d mBm)\n",
+       REG_DBG_PRINT("%d KHz - %d KHz @ %s), (%s mBi, %d mBm)\n",
                      freq_range->start_freq_khz, freq_range->end_freq_khz,
-                     freq_range->max_bandwidth_khz, max_antenna_gain,
+                     bw, max_antenna_gain,
                      power_rule->max_eirp);
 }
 #else
-static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
+static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
+                                   struct ieee80211_channel *chan,
                                    const struct ieee80211_reg_rule *reg_rule)
 {
        return;
@@ -1022,17 +1033,16 @@ static void handle_channel(struct wiphy *wiphy,
                return;
        }
 
-       chan_reg_rule_print_dbg(chan, reg_rule);
+       regd = reg_get_regdomain(wiphy);
+       chan_reg_rule_print_dbg(regd, chan, reg_rule);
 
        power_rule = &reg_rule->power_rule;
        freq_range = &reg_rule->freq_range;
 
        max_bandwidth_khz = freq_range->max_bandwidth_khz;
        /* Check if auto calculation requested */
-       if (!max_bandwidth_khz) {
-               regd = reg_get_regdomain(wiphy);
+       if (reg_rule->flags & NL80211_RRF_AUTO_BW)
                max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
-       }
 
        if (max_bandwidth_khz < MHZ_TO_KHZ(40))
                bw_flags = IEEE80211_CHAN_NO_HT40;
@@ -1437,14 +1447,14 @@ static void handle_channel_custom(struct wiphy *wiphy,
                return;
        }
 
-       chan_reg_rule_print_dbg(chan, reg_rule);
+       chan_reg_rule_print_dbg(regd, chan, reg_rule);
 
        power_rule = &reg_rule->power_rule;
        freq_range = &reg_rule->freq_range;
 
        max_bandwidth_khz = freq_range->max_bandwidth_khz;
        /* Check if auto calculation requested */
-       if (!max_bandwidth_khz)
+       if (reg_rule->flags & NL80211_RRF_AUTO_BW)
                max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
 
        if (max_bandwidth_khz < MHZ_TO_KHZ(40))
@@ -1788,7 +1798,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
                return;
        case NL80211_REGDOM_SET_BY_USER:
                treatment = reg_process_hint_user(reg_request);
-               if (treatment == REG_REQ_OK ||
+               if (treatment == REG_REQ_IGNORE ||
                    treatment == REG_REQ_ALREADY_SET)
                        return;
                queue_delayed_work(system_power_efficient_wq,
@@ -2254,11 +2264,12 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
                freq_range = &reg_rule->freq_range;
                power_rule = &reg_rule->power_rule;
 
-               if (!freq_range->max_bandwidth_khz)
-                       snprintf(bw, 32, "%d KHz, AUTO",
+               if (reg_rule->flags & NL80211_RRF_AUTO_BW)
+                       snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO",
+                                freq_range->max_bandwidth_khz,
                                 reg_get_max_bandwidth(rd, reg_rule));
                else
-                       snprintf(bw, 32, "%d KHz",
+                       snprintf(bw, sizeof(bw), "%d KHz",
                                 freq_range->max_bandwidth_khz);
 
                /*
@@ -2481,6 +2492,7 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
 int set_regdom(const struct ieee80211_regdomain *rd)
 {
        struct regulatory_request *lr;
+       bool user_reset = false;
        int r;
 
        if (!reg_is_valid_request(rd->alpha2)) {
@@ -2497,6 +2509,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
                break;
        case NL80211_REGDOM_SET_BY_USER:
                r = reg_set_rd_user(rd, lr);
+               user_reset = true;
                break;
        case NL80211_REGDOM_SET_BY_DRIVER:
                r = reg_set_rd_driver(rd, lr);
@@ -2510,8 +2523,14 @@ int set_regdom(const struct ieee80211_regdomain *rd)
        }
 
        if (r) {
-               if (r == -EALREADY)
+               switch (r) {
+               case -EALREADY:
                        reg_set_request_processed();
+                       break;
+               default:
+                       /* Back to world regulatory in case of errors */
+                       restore_regulatory_settings(user_reset);
+               }
 
                kfree(rd);
                return r;
index 5eaeed59db07651de6305320187f127c9fdd8b65..aabccf13e07b6860ef92ddc637a7879a8f961aab 100644 (file)
@@ -1468,9 +1468,10 @@ TRACE_EVENT(rdev_sched_scan_start,
 TRACE_EVENT(rdev_tdls_mgmt,
        TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
                 u8 *peer, u8 action_code, u8 dialog_token,
-                u16 status_code, const u8 *buf, size_t len),
+                u16 status_code, u32 peer_capability,
+                const u8 *buf, size_t len),
        TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code,
-               buf, len),
+               peer_capability, buf, len),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                NETDEV_ENTRY
@@ -1478,6 +1479,7 @@ TRACE_EVENT(rdev_tdls_mgmt,
                __field(u8, action_code)
                __field(u8, dialog_token)
                __field(u16, status_code)
+               __field(u32, peer_capability)
                __dynamic_array(u8, buf, len)
        ),
        TP_fast_assign(
@@ -1487,13 +1489,15 @@ TRACE_EVENT(rdev_tdls_mgmt,
                __entry->action_code = action_code;
                __entry->dialog_token = dialog_token;
                __entry->status_code = status_code;
+               __entry->peer_capability = peer_capability;
                memcpy(__get_dynamic_array(buf), buf, len);
        ),
        TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, "
-                 "dialog_token: %u, status_code: %u, buf: %#.2x ",
+                 "dialog_token: %u, status_code: %u, peer_capability: %u buf: %#.2x ",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
                  __entry->action_code, __entry->dialog_token,
-                 __entry->status_code, ((u8 *)__get_dynamic_array(buf))[0])
+                 __entry->status_code, __entry->peer_capability,
+                 ((u8 *)__get_dynamic_array(buf))[0])
 );
 
 TRACE_EVENT(rdev_dump_survey,
index ad03af385556e7757a7582b53de36d79a0ff37f2..2bb685f3e8fc7a69b195434591c59615ea9cc28b 100644 (file)
@@ -1285,7 +1285,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
        enum cfg80211_chan_mode chmode;
        int num_different_channels = 0;
        int total = 1;
-       bool radar_required = false;
        int i, j;
 
        ASSERT_RTNL();
@@ -1293,35 +1292,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
        if (WARN_ON(hweight32(radar_detect) > 1))
                return -EINVAL;
 
-       switch (iftype) {
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_MESH_POINT:
-       case NL80211_IFTYPE_P2P_GO:
-       case NL80211_IFTYPE_WDS:
-               /* if the interface could potentially choose a DFS channel,
-                * then mark DFS as required.
-                */
-               if (!chan) {
-                       if (chanmode != CHAN_MODE_UNDEFINED && radar_detect)
-                               radar_required = true;
-                       break;
-               }
-               radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
-               break;
-       case NL80211_IFTYPE_P2P_CLIENT:
-       case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_P2P_DEVICE:
-       case NL80211_IFTYPE_MONITOR:
-               break;
-       case NUM_NL80211_IFTYPES:
-       case NL80211_IFTYPE_UNSPECIFIED:
-       default:
-               return -EINVAL;
-       }
-
-       if (radar_required && !radar_detect)
+       if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
                return -EINVAL;
 
        /* Always allow software iftypes */
index bb3669d973a7b33178770e25be49f71940e7a21b..f02f511b710741e1779d389ac69bfc75a17ab42f 100644 (file)
@@ -1156,7 +1156,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
        if (hlist_unhashed(&pol->bydst))
                return NULL;
 
-       hlist_del(&pol->bydst);
+       hlist_del_init(&pol->bydst);
        hlist_del(&pol->byidx);
        list_del(&pol->walk.all);
        net->xfrm.policy_count[dir]--;
@@ -2913,15 +2913,19 @@ static int __net_init xfrm_net_init(struct net *net)
        rv = xfrm_sysctl_init(net);
        if (rv < 0)
                goto out_sysctl;
+       rv = flow_cache_init(net);
+       if (rv < 0)
+               goto out;
 
        /* Initialize the per-net locks here */
        spin_lock_init(&net->xfrm.xfrm_state_lock);
        rwlock_init(&net->xfrm.xfrm_policy_lock);
        mutex_init(&net->xfrm.xfrm_cfg_mutex);
 
-       flow_cache_init(net);
        return 0;
 
+out:
+       xfrm_sysctl_fini(net);
 out_sysctl:
        xfrm_policy_fini(net);
 out_policy:
@@ -2934,6 +2938,7 @@ out_statistics:
 
 static void __net_exit xfrm_net_exit(struct net *net)
 {
+       flow_cache_fini(net);
        xfrm_sysctl_fini(net);
        xfrm_policy_fini(net);
        xfrm_state_fini(net);
index cee850c761657362d90529edf61fa74f2335d45a..8e9c781a6bbaaba83e4af4a31ac7a07a70dd6c71 100644 (file)
@@ -1171,6 +1171,11 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig)
        }
        x->props.aalgo = orig->props.aalgo;
 
+       if (orig->aead) {
+               x->aead = xfrm_algo_aead_clone(orig->aead);
+               if (!x->aead)
+                       goto error;
+       }
        if (orig->ealg) {
                x->ealg = xfrm_algo_clone(orig->ealg);
                if (!x->ealg)
@@ -1211,6 +1216,9 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig)
        x->props.flags = orig->props.flags;
        x->props.extra_flags = orig->props.extra_flags;
 
+       x->tfcpad = orig->tfcpad;
+       x->replay_maxdiff = orig->replay_maxdiff;
+       x->replay_maxage = orig->replay_maxage;
        x->curlft.add_time = orig->curlft.add_time;
        x->km.state = orig->km.state;
        x->km.seq = orig->km.seq;
@@ -1223,11 +1231,12 @@ out:
        return NULL;
 }
 
-/* net->xfrm.xfrm_state_lock is held */
 struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
 {
        unsigned int h;
-       struct xfrm_state *x;
+       struct xfrm_state *x = NULL;
+
+       spin_lock_bh(&net->xfrm.xfrm_state_lock);
 
        if (m->reqid) {
                h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr,
@@ -1244,7 +1253,7 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                                             m->old_family))
                                continue;
                        xfrm_state_hold(x);
-                       return x;
+                       break;
                }
        } else {
                h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr,
@@ -1259,11 +1268,13 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                                             m->old_family))
                                continue;
                        xfrm_state_hold(x);
-                       return x;
+                       break;
                }
        }
 
-       return NULL;
+       spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+
+       return x;
 }
 EXPORT_SYMBOL(xfrm_migrate_state_find);
 
@@ -1458,7 +1469,7 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
 {
        int err = 0;
        struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
-       struct net *net = xs_net(*dst);
+       struct net *net = xs_net(*src);
 
        if (!afinfo)
                return -EAFNOSUPPORT;
index 903725b8cc70b8cf72af5aa341376ad8f36de466..cdd9e9c7ff0e10a9669a86ef308bead8bfbc525e 100644 (file)
 #include <linux/in6.h>
 #endif
 
-static inline int aead_len(struct xfrm_algo_aead *alg)
-{
-       return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
-}
-
 static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
 {
        struct nlattr *rt = attrs[type];
index 49392ecbef17baf113bb9e3771384d06413bbb25..79c059e708600b04b63f8bc27cca94b485684cc8 100644 (file)
@@ -152,6 +152,7 @@ ld_flags       = $(LDFLAGS) $(ldflags-y)
 dtc_cpp_flags  = -Wp,-MD,$(depfile).pre.tmp -nostdinc                    \
                 -I$(srctree)/arch/$(SRCARCH)/boot/dts                   \
                 -I$(srctree)/arch/$(SRCARCH)/boot/dts/include           \
+                -I$(srctree)/drivers/of/testcase-data                   \
                 -undef -D__DTS__
 
 # Finds the multi-part object the current object will be linked into
index ef474098d9f1d1e2609221d3d3571c1f29d1b599..17fa901418ae6a491ba61f3814a1143e2a62bfde 100644 (file)
@@ -257,7 +257,7 @@ case "$arg" in
                 && compr="lzop -9 -f"
                echo "$output_file" | grep -q "\.lz4$" \
                 && [ -x "`which lz4 2> /dev/null`" ] \
-                && compr="lz4 -9 -f"
+                && compr="lz4 -l -9 -f"
                echo "$output_file" | grep -q "\.cpio$" && compr="cat"
                shift
                ;;
index 40610984a1b54b06c579f953dabeb5ddb1304525..99a45fdc1bbfa9a15e7bbd6e4f9ec14a8a8c2357 100644 (file)
@@ -1502,6 +1502,16 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
 #define R_ARM_JUMP24   29
 #endif
 
+#ifndef        R_ARM_THM_CALL
+#define        R_ARM_THM_CALL          10
+#endif
+#ifndef        R_ARM_THM_JUMP24
+#define        R_ARM_THM_JUMP24        30
+#endif
+#ifndef        R_ARM_THM_JUMP19
+#define        R_ARM_THM_JUMP19        51
+#endif
+
 static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
 {
        unsigned int r_typ = ELF_R_TYPE(r->r_info);
@@ -1515,6 +1525,9 @@ static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
        case R_ARM_PC24:
        case R_ARM_CALL:
        case R_ARM_JUMP24:
+       case R_ARM_THM_CALL:
+       case R_ARM_THM_JUMP24:
+       case R_ARM_THM_JUMP19:
                /* From ARM ABI: ((S + A) | T) - P */
                r->r_addend = (int)(long)(elf->hdr +
                              sechdr->sh_offset +
index d46cbc5e335e9c330ccd74a08fcbf78aeafe8c96..2fb2576dc6448b3c1020dc311e0d81bfe77fb768 100644 (file)
@@ -1000,7 +1000,11 @@ static int keyring_detect_cycle_iterator(const void *object,
 
        kenter("{%d}", key->serial);
 
-       BUG_ON(key != ctx->match_data);
+       /* We might get a keyring with matching index-key that is nonetheless a
+        * different keyring. */
+       if (key != ctx->match_data)
+               return 0;
+
        ctx->result = ERR_PTR(-EDEADLK);
        return 1;
 }
index c0f4988421292f0ab6610421704ee21381b59a0f..9c5cdc2caaef7637b4bf9178a8efcbe69558c6b9 100644 (file)
@@ -3338,10 +3338,10 @@ static int filename_write_helper(void *key, void *data, void *ptr)
        if (rc)
                return rc;
 
-       buf[0] = ft->stype;
-       buf[1] = ft->ttype;
-       buf[2] = ft->tclass;
-       buf[3] = otype->otype;
+       buf[0] = cpu_to_le32(ft->stype);
+       buf[1] = cpu_to_le32(ft->ttype);
+       buf[2] = cpu_to_le32(ft->tclass);
+       buf[3] = cpu_to_le32(otype->otype);
 
        rc = put_entry(buf, sizeof(u32), 4, fp);
        if (rc)
index df3652ad15ef36224fdbc121ee1018116bab28c0..8ed0bcc0138637e69e19ff7056b99a86fac09fa6 100644 (file)
@@ -1026,6 +1026,9 @@ static void ad1884_fixup_thinkpad(struct hda_codec *codec,
                spec->gen.keep_eapd_on = 1;
                spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
                spec->eapd_nid = 0x12;
+               /* Analog PC Beeper - allow firmware/ACPI beeps */
+               spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
+               spec->gen.beep_nid = 0; /* no digital beep */
        }
 }
 
@@ -1092,6 +1095,7 @@ static int patch_ad1884(struct hda_codec *codec)
        spec = codec->spec;
 
        spec->gen.mixer_nid = 0x20;
+       spec->gen.mixer_merge_nid = 0x21;
        spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
 
index 54d14793725a7dd93623083d29f72f41a5ddc4bd..46ecdbb9053f337ee6f1b199d9babdeb043d72d5 100644 (file)
@@ -2661,60 +2661,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
        return false;
 }
 
-/*
- * PCM stuffs
- */
-static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid,
-                                u32 stream_tag,
-                                int channel_id, int format)
-{
-       unsigned int oldval, newval;
-
-       if (!nid)
-               return;
-
-       snd_printdd(
-                  "ca0132_setup_stream: NID=0x%x, stream=0x%x, "
-                  "channel=%d, format=0x%x\n",
-                  nid, stream_tag, channel_id, format);
-
-       /* update the format-id if changed */
-       oldval = snd_hda_codec_read(codec, nid, 0,
-                                   AC_VERB_GET_STREAM_FORMAT,
-                                   0);
-       if (oldval != format) {
-               msleep(20);
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_STREAM_FORMAT,
-                                   format);
-       }
-
-       oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-       newval = (stream_tag << 4) | channel_id;
-       if (oldval != newval) {
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_CHANNEL_STREAMID,
-                                   newval);
-       }
-}
-
-static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
-{
-       unsigned int val;
-
-       if (!nid)
-               return;
-
-       snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid);
-
-       val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-       if (!val)
-               return;
-
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-}
-
 /*
  * PCM callbacks
  */
@@ -2726,7 +2672,7 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 {
        struct ca0132_spec *spec = codec->spec;
 
-       ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
+       snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
 
        return 0;
 }
@@ -2745,7 +2691,7 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
        if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
                msleep(50);
 
-       ca0132_cleanup_stream(codec, spec->dacs[0]);
+       snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
 
        return 0;
 }
@@ -2822,10 +2768,8 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                        unsigned int format,
                                        struct snd_pcm_substream *substream)
 {
-       struct ca0132_spec *spec = codec->spec;
-
-       ca0132_setup_stream(codec, spec->adcs[substream->number],
-                           stream_tag, 0, format);
+       snd_hda_codec_setup_stream(codec, hinfo->nid,
+                                  stream_tag, 0, format);
 
        return 0;
 }
@@ -2839,7 +2783,7 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
        if (spec->dsp_state == DSP_DOWNLOADING)
                return 0;
 
-       ca0132_cleanup_stream(codec, hinfo->nid);
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
        return 0;
 }
 
@@ -4742,6 +4686,8 @@ static int patch_ca0132(struct hda_codec *codec)
                return err;
 
        codec->patch_ops = ca0132_patch_ops;
+       codec->pcm_format_first = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
index a9a83b85517aa0738bed1e2ee29b39ae945c37e4..8d0a84436674bf893ec871173a53b00b89f92c68 100644 (file)
@@ -3616,6 +3616,19 @@ static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
        }
 }
 
+static void alc_no_shutup(struct hda_codec *codec)
+{
+}
+
+static void alc_fixup_no_shutup(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               spec->shutup = alc_no_shutup;
+       }
+}
+
 static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -3844,6 +3857,7 @@ enum {
        ALC269_FIXUP_HP_GPIO_LED,
        ALC269_FIXUP_INV_DMIC,
        ALC269_FIXUP_LENOVO_DOCK,
+       ALC269_FIXUP_NO_SHUTUP,
        ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
        ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
        ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
@@ -4020,6 +4034,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_inv_dmic_0x12,
        },
+       [ALC269_FIXUP_NO_SHUTUP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_no_shutup,
+       },
        [ALC269_FIXUP_LENOVO_DOCK] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -4253,6 +4271,7 @@ static const struct hda_fixup alc269_fixups[] = {
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
@@ -4308,7 +4327,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0657, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
@@ -4317,6 +4338,54 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
+       /* ALC282 */
+       SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c1, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22cd, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       /* ALC290 */
+       SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2280, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2281, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2289, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c6, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -4354,6 +4423,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
        SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5113,7 +5183,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE),
-       SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_AUTO_MUTE),
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
        SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A_CHMAP),
        SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP),
index 7311badf6a946e3ef33fa5281ed5d5e4f165482e..3bc29c9b25296d6ed058eaf552bf71bdba356cab 100644 (file)
@@ -83,6 +83,7 @@ enum {
        STAC_DELL_M6_BOTH,
        STAC_DELL_EQ,
        STAC_ALIENWARE_M17X,
+       STAC_92HD89XX_HP_FRONT_JACK,
        STAC_92HD73XX_MODELS
 };
 
@@ -97,6 +98,7 @@ enum {
        STAC_92HD83XXX_HP_LED,
        STAC_92HD83XXX_HP_INV_LED,
        STAC_92HD83XXX_HP_MIC_LED,
+       STAC_HP_LED_GPIO10,
        STAC_92HD83XXX_HEADSET_JACK,
        STAC_92HD83XXX_HP,
        STAC_HP_ENVY_BASS,
@@ -1795,6 +1797,12 @@ static const struct hda_pintbl intel_dg45id_pin_configs[] = {
        {}
 };
 
+static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = {
+       { 0x0a, 0x02214030 },
+       { 0x0b, 0x02A19010 },
+       {}
+};
+
 static void stac92hd73xx_fixup_ref(struct hda_codec *codec,
                                   const struct hda_fixup *fix, int action)
 {
@@ -1913,6 +1921,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
        [STAC_92HD73XX_NO_JD] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = stac92hd73xx_fixup_no_jd,
+       },
+       [STAC_92HD89XX_HP_FRONT_JACK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac92hd89xx_hp_front_jack_pin_configs,
        }
 };
 
@@ -1973,6 +1985,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
                      "Alienware M17x", STAC_ALIENWARE_M17X),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
                      "Alienware M17x R3", STAC_DELL_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
+                               "unknown HP", STAC_92HD89XX_HP_FRONT_JACK),
        {} /* terminator */
 };
 
@@ -2117,6 +2131,17 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
        }
 }
 
+static void stac92hd83xxx_fixup_hp_led_gpio10(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gpio_led = 0x10; /* GPIO4 */
+               spec->default_polarity = 0;
+       }
+}
+
 static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec,
                                   const struct hda_fixup *fix, int action)
 {
@@ -2611,6 +2636,12 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = {
                .chained = true,
                .chain_id = STAC_92HD83XXX_HP,
        },
+       [STAC_HP_LED_GPIO10] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_hp_led_gpio10,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP,
+       },
        [STAC_92HD83XXX_HEADSET_JACK] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = stac92hd83xxx_fixup_headset_jack,
@@ -2689,6 +2720,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888,
                          "HP Envy Spectre", STAC_HP_ENVY_BASS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1899,
+                         "HP Folio 13", STAC_HP_LED_GPIO10),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
                          "HP Folio", STAC_HP_BNB13_EQ),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8,
index 54f74f8cbb754a0e66aecc3953fff0c8ba63966c..4544d8eb1452b24638c969ed15432a6f41e98ef8 100644 (file)
@@ -11,7 +11,7 @@ config SND_BF5XX_I2S
 
 config SND_BF5XX_SOC_SSM2602
        tristate "SoC SSM2602 Audio Codec Add-On Card support"
-       depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+       depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
        select SND_BF5XX_SOC_I2S if !BF60x
        select SND_BF6XX_SOC_I2S if BF60x
        select SND_SOC_SSM2602
@@ -21,10 +21,9 @@ config SND_BF5XX_SOC_SSM2602
 
 config SND_SOC_BFIN_EVAL_ADAU1701
        tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
-       depends on SND_BF5XX_I2S
+       depends on SND_BF5XX_I2S && I2C
        select SND_BF5XX_SOC_I2S
        select SND_SOC_ADAU1701
-       select I2C
        help
          Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ
          board connected to one of the Blackfin evaluation boards like the
@@ -45,7 +44,7 @@ config SND_SOC_BFIN_EVAL_ADAU1373
 
 config SND_SOC_BFIN_EVAL_ADAV80X
        tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
-       depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+       depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
        select SND_BF5XX_SOC_I2S
        select SND_SOC_ADAV80X
        help
@@ -58,7 +57,7 @@ config SND_SOC_BFIN_EVAL_ADAV80X
 
 config SND_BF5XX_SOC_AD1836
        tristate "SoC AD1836 Audio support for BF5xx"
-       depends on SND_BF5XX_I2S
+       depends on SND_BF5XX_I2S && SPI_MASTER
        select SND_BF5XX_SOC_I2S
        select SND_SOC_AD1836
        help
@@ -66,7 +65,7 @@ config SND_BF5XX_SOC_AD1836
 
 config SND_BF5XX_SOC_AD193X
        tristate "SoC AD193X Audio support for Blackfin"
-       depends on SND_BF5XX_I2S
+       depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
        select SND_BF5XX_SOC_I2S
        select SND_SOC_AD193X
        help
index 75d0ad5d2dcb38107934536ba7ef93410025c2f6..647a72cda005a5cc4f8b362fefe8aa1ad3f68a76 100644 (file)
@@ -1328,6 +1328,9 @@ static int pm860x_probe(struct snd_soc_codec *codec)
        pm860x->codec = codec;
 
        codec->control_data = pm860x->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
+       if (ret)
+               return ret;
 
        for (i = 0; i < 4; i++) {
                ret = request_threaded_irq(pm860x->irq[i], NULL,
index 7257a8885f426d7cf05b017fbda1aa3f01abe236..34d965a4a040c91d861a8d2f8a3ef183b95bc5e8 100644 (file)
@@ -57,8 +57,8 @@ static const u16 ad1980_reg[] = {
 static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
                "Stereo Mix", "Mono Mix", "Phone"};
 
-static const struct soc_enum ad1980_cap_src =
-       SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel);
+static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src,
+                           AC97_REC_SEL, 8, 0, ad1980_rec_sel);
 
 static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = {
 SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
index f295b65699105897743fad1ecbc4439a71e58f0e..f4d965ebc29e8320469becd09a3ac58a2668e8de 100644 (file)
@@ -1268,11 +1268,23 @@ static struct snd_soc_dai_driver da732x_dai[] = {
        },
 };
 
+static bool da732x_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case DA732X_REG_HPL_DAC_OFF_CNTL:
+       case DA732X_REG_HPR_DAC_OFF_CNTL:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static const struct regmap_config da732x_regmap = {
        .reg_bits               = 8,
        .val_bits               = 8,
 
        .max_register           = DA732X_MAX_REG,
+       .volatile_reg           = da732x_volatile,
        .reg_defaults           = da732x_reg_cache,
        .num_reg_defaults       = ARRAY_SIZE(da732x_reg_cache),
        .cache_type             = REGCACHE_RBTREE,
index 52b79a487ac7db318dd252fe30befd6a3c56b2ec..422812613a28b1cff117b1adfee2029b69e6049b 100644 (file)
@@ -1523,8 +1523,15 @@ static int da9055_remove(struct i2c_client *client)
        return 0;
 }
 
+/*
+ * DO NOT change the device Ids. The naming is intentionally specific as both
+ * the CODEC and PMIC parts of this chip are instantiated separately as I2C
+ * devices (both have configurable I2C addresses, and are to all intents and
+ * purposes separate). As a result there are specific DA9055 Ids for CODEC
+ * and PMIC, which must be different to operate together.
+ */
 static const struct i2c_device_id da9055_i2c_id[] = {
-       { "da9055", 0 },
+       { "da9055-codec", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
@@ -1532,7 +1539,7 @@ MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
 /* I2C codec control layer */
 static struct i2c_driver da9055_i2c_driver = {
        .driver = {
-               .name = "da9055",
+               .name = "da9055-codec",
                .owner = THIS_MODULE,
        },
        .probe          = da9055_i2c_probe,
index 5839048ec4674e5d20cc5f06e206c2210977999e..cb736ddc446dc0bc5a387dc3ebc28e4bb0fee9aa 100644 (file)
@@ -140,13 +140,17 @@ static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"};
 static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"};
 
 static const struct soc_enum isabelle_rx1_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts),
-       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts),
+       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3,
+                       ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5,
+                       ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts),
 };
 
 static const struct soc_enum isabelle_rx2_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts),
-       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts),
+       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2,
+                       ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4,
+                       ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts),
 };
 
 /* Headset DAC playback switches */
@@ -161,13 +165,17 @@ static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"};
 static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"};
 
 static const struct soc_enum isabelle_atx_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts),
-       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0,
+                       ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts),
 };
 
 static const struct soc_enum isabelle_vtx_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts),
-       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6,
+                       ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0,
+                       ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts),
 };
 
 static const struct snd_kcontrol_new atx_mux_controls =
@@ -183,17 +191,13 @@ static const char *isabelle_amic1_texts[] = {
 /* Left analog microphone selection */
 static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"};
 
-static const struct soc_enum isabelle_amic1_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5,
-                       ARRAY_SIZE(isabelle_amic1_texts),
-                       isabelle_amic1_texts),
-};
+static SOC_ENUM_SINGLE_DECL(isabelle_amic1_enum,
+                           ISABELLE_AMIC_CFG_REG, 5,
+                           isabelle_amic1_texts);
 
-static const struct soc_enum isabelle_amic2_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4,
-                       ARRAY_SIZE(isabelle_amic2_texts),
-                       isabelle_amic2_texts),
-};
+static SOC_ENUM_SINGLE_DECL(isabelle_amic2_enum,
+                           ISABELLE_AMIC_CFG_REG, 4,
+                           isabelle_amic2_texts);
 
 static const struct snd_kcontrol_new amic1_control =
        SOC_DAPM_ENUM("Route", isabelle_amic1_enum);
@@ -206,16 +210,20 @@ static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"};
 static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"};
 
 static const struct soc_enum isabelle_st_audio_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1,
+       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_st_audio_texts),
                        isabelle_st_audio_texts),
-       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1,
+       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_st_audio_texts),
                        isabelle_st_audio_texts),
 };
 
 static const struct soc_enum isabelle_st_voice_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1,
+       SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_st_voice_texts),
                        isabelle_st_voice_texts),
-       SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1,
+       SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_st_voice_texts),
                        isabelle_st_voice_texts),
 };
 
index 51f9b3d16b41dbf4cc80dddc6d0a081ccb83fe90..9f714ea86613cc6939c62c3a420dc0c2ce07bb17 100644 (file)
@@ -336,6 +336,7 @@ static bool max98090_readable_register(struct device *dev, unsigned int reg)
        case M98090_REG_RECORD_TDM_SLOT:
        case M98090_REG_SAMPLE_RATE:
        case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E:
+       case M98090_REG_REVISION_ID:
                return true;
        default:
                return false;
@@ -1769,16 +1770,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       ret = regcache_sync(max98090->regmap);
-
-                       if (ret != 0) {
-                               dev_err(codec->dev,
-                                       "Failed to sync cache: %d\n", ret);
-                               return ret;
-                       }
-               }
-
                if (max98090->jack_state == M98090_JACK_STATE_HEADSET) {
                        /*
                         * Set to normal bias level.
@@ -1792,6 +1783,16 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regcache_sync(max98090->regmap);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to sync cache: %d\n", ret);
+                               return ret;
+                       }
+               }
+               break;
+
        case SND_SOC_BIAS_OFF:
                /* Set internal pull-up to lowest power mode */
                snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
index a3fb411796364a683d554b6278ba9bda6b942326..886924934aa5c7db067f352aafc4113d5ab97c06 100644 (file)
@@ -2093,6 +2093,7 @@ MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
 #ifdef CONFIG_ACPI
 static struct acpi_device_id rt5640_acpi_match[] = {
        { "INT33CA", 0 },
+       { "10EC5640", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
index 52e7cb08434bd281354c4a34f520f16c38b0446f..fa2b8e07f420dd9c14ac0dc944babfe66dfbe2b2 100644 (file)
@@ -210,7 +210,7 @@ out:
 static int si476x_codec_probe(struct snd_soc_codec *codec)
 {
        codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
-       return 0;
+       return snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
 }
 
 static struct snd_soc_dai_ops si476x_dai_ops = {
index 06edb396e733f1ad2ef26698a41b4eb1fdc18ea6..2735361a4c3cfc5fbc652ee10d62ec2728626184 100644 (file)
@@ -187,42 +187,42 @@ static const unsigned int sta32x_limiter_drc_release_tlv[] = {
        13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
 };
 
-static const struct soc_enum sta32x_drc_ac_enum =
-       SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
-                       2, sta32x_drc_ac);
-static const struct soc_enum sta32x_auto_eq_enum =
-       SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
-                       3, sta32x_auto_eq_mode);
-static const struct soc_enum sta32x_auto_gc_enum =
-       SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
-                       4, sta32x_auto_gc_mode);
-static const struct soc_enum sta32x_auto_xo_enum =
-       SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
-                       16, sta32x_auto_xo_mode);
-static const struct soc_enum sta32x_preset_eq_enum =
-       SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
-                       32, sta32x_preset_eq_mode);
-static const struct soc_enum sta32x_limiter_ch1_enum =
-       SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
-                       3, sta32x_limiter_select);
-static const struct soc_enum sta32x_limiter_ch2_enum =
-       SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
-                       3, sta32x_limiter_select);
-static const struct soc_enum sta32x_limiter_ch3_enum =
-       SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
-                       3, sta32x_limiter_select);
-static const struct soc_enum sta32x_limiter1_attack_rate_enum =
-       SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT,
-                       16, sta32x_limiter_attack_rate);
-static const struct soc_enum sta32x_limiter2_attack_rate_enum =
-       SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT,
-                       16, sta32x_limiter_attack_rate);
-static const struct soc_enum sta32x_limiter1_release_rate_enum =
-       SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT,
-                       16, sta32x_limiter_release_rate);
-static const struct soc_enum sta32x_limiter2_release_rate_enum =
-       SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT,
-                       16, sta32x_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
+                           STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
+                           sta32x_drc_ac);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum,
+                           STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
+                           sta32x_auto_eq_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum,
+                           STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
+                           sta32x_auto_gc_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum,
+                           STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
+                           sta32x_auto_xo_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum,
+                           STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
+                           sta32x_preset_eq_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum,
+                           STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
+                           sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum,
+                           STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
+                           sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum,
+                           STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
+                           sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum,
+                           STA32X_L1AR, STA32X_LxA_SHIFT,
+                           sta32x_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum,
+                           STA32X_L2AR, STA32X_LxA_SHIFT,
+                           sta32x_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum,
+                           STA32X_L1AR, STA32X_LxR_SHIFT,
+                           sta32x_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum,
+                           STA32X_L2AR, STA32X_LxR_SHIFT,
+                           sta32x_limiter_release_rate);
 
 /* byte array controls for setting biquad, mixer, scaling coefficients;
  * for biquads all five coefficients need to be set in one go,
@@ -331,7 +331,7 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
 
 static int sta32x_cache_sync(struct snd_soc_codec *codec)
 {
-       struct sta32x_priv *sta32x = codec->control_data;
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
        unsigned int mute;
        int rc;
 
@@ -434,7 +434,7 @@ SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0,
 SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
 SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
 SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
-SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
+SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),
 
 /* depending on mode, the attack/release thresholds have
  * two different enum definitions; provide both
index 48dc7d2fee36fc07c236f6e9a09ea74cdb38d824..6d684d934f4de1e2b2c43dfc18d5659ada570cf1 100644 (file)
@@ -117,19 +117,23 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 static const char *wm8400_digital_sidetone[] =
        {"None", "Left ADC", "Right ADC", "Reserved"};
 
-static const struct soc_enum wm8400_left_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
-               WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8400_left_digital_sidetone_enum,
+                           WM8400_DIGITAL_SIDE_TONE,
+                           WM8400_ADC_TO_DACL_SHIFT,
+                           wm8400_digital_sidetone);
 
-static const struct soc_enum wm8400_right_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
-               WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8400_right_digital_sidetone_enum,
+                           WM8400_DIGITAL_SIDE_TONE,
+                           WM8400_ADC_TO_DACR_SHIFT,
+                           wm8400_digital_sidetone);
 
 static const char *wm8400_adcmode[] =
        {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
 
-static const struct soc_enum wm8400_right_adcmode_enum =
-SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode);
+static SOC_ENUM_SINGLE_DECL(wm8400_right_adcmode_enum,
+                           WM8400_ADC_CTRL,
+                           WM8400_ADC_HPF_CUT_SHIFT,
+                           wm8400_adcmode);
 
 static const struct snd_kcontrol_new wm8400_snd_controls[] = {
 /* INMIXL */
@@ -422,9 +426,10 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
 static const char *wm8400_ainlmux[] =
        {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
 
-static const struct soc_enum wm8400_ainlmux_enum =
-SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT,
-       ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux);
+static SOC_ENUM_SINGLE_DECL(wm8400_ainlmux_enum,
+                           WM8400_INPUT_MIXER1,
+                           WM8400_AINLMODE_SHIFT,
+                           wm8400_ainlmux);
 
 static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls =
 SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
@@ -435,9 +440,10 @@ SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
 static const char *wm8400_ainrmux[] =
        {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
 
-static const struct soc_enum wm8400_ainrmux_enum =
-SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT,
-       ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux);
+static SOC_ENUM_SINGLE_DECL(wm8400_ainrmux_enum,
+                           WM8400_INPUT_MIXER1,
+                           WM8400_AINRMODE_SHIFT,
+                           wm8400_ainrmux);
 
 static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls =
 SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum);
index 89a18d82f303e168f874a418840a9d33a4923910..5bce2101348514aa6508dc9dac7f895d176ae0d9 100644 (file)
@@ -196,8 +196,8 @@ static const char *ain_text[] = {
        "AIN5", "AIN6", "AIN7", "AIN8"
 };
 
-static const struct soc_enum ain_enum =
-       SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text);
+static SOC_ENUM_DOUBLE_DECL(ain_enum,
+                           WM8770_ADCMUX, 0, 4, ain_text);
 
 static const struct snd_kcontrol_new ain_mux =
        SOC_DAPM_ENUM("Capture Mux", ain_enum);
index e98bc7038a086b39231ecbb5196fb7a40fc92d1e..43c2201cb90131ebdb66e2f10326f4c904700011 100644 (file)
@@ -304,53 +304,53 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
 
 static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" };
 
-static const struct soc_enum mic_bias_level =
-SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt);
+static SOC_ENUM_SINGLE_DECL(mic_bias_level,
+                           WM8900_REG_INCTL, 8, mic_bias_level_txt);
 
 static const char *dac_mute_rate_txt[] = { "Fast", "Slow" };
 
-static const struct soc_enum dac_mute_rate =
-SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt);
+static SOC_ENUM_SINGLE_DECL(dac_mute_rate,
+                           WM8900_REG_DACCTRL, 7, dac_mute_rate_txt);
 
 static const char *dac_deemphasis_txt[] = {
        "Disabled", "32kHz", "44.1kHz", "48kHz"
 };
 
-static const struct soc_enum dac_deemphasis =
-SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt);
+static SOC_ENUM_SINGLE_DECL(dac_deemphasis,
+                           WM8900_REG_DACCTRL, 4, dac_deemphasis_txt);
 
 static const char *adc_hpf_cut_txt[] = {
        "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"
 };
 
-static const struct soc_enum adc_hpf_cut =
-SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt);
+static SOC_ENUM_SINGLE_DECL(adc_hpf_cut,
+                           WM8900_REG_ADCCTRL, 5, adc_hpf_cut_txt);
 
 static const char *lr_txt[] = {
        "Left", "Right"
 };
 
-static const struct soc_enum aifl_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(aifl_src,
+                           WM8900_REG_AUDIO1, 15, lr_txt);
 
-static const struct soc_enum aifr_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(aifr_src,
+                           WM8900_REG_AUDIO1, 14, lr_txt);
 
-static const struct soc_enum dacl_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(dacl_src,
+                           WM8900_REG_AUDIO2, 15, lr_txt);
 
-static const struct soc_enum dacr_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(dacr_src,
+                           WM8900_REG_AUDIO2, 14, lr_txt);
 
 static const char *sidetone_txt[] = {
        "Disabled", "Left ADC", "Right ADC"
 };
 
-static const struct soc_enum dacl_sidetone =
-SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt);
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone,
+                           WM8900_REG_SIDETONE, 2, sidetone_txt);
 
-static const struct soc_enum dacr_sidetone =
-SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt);
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone,
+                           WM8900_REG_SIDETONE, 0, sidetone_txt);
 
 static const struct snd_kcontrol_new wm8900_snd_controls[] = {
 SOC_ENUM("Mic Bias Level", mic_bias_level),
@@ -496,8 +496,8 @@ SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),
 
 static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" };
 
-static const struct soc_enum wm8900_lineout2_lp_mux =
-SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm8900_lp_mux);
+static SOC_ENUM_SINGLE_DECL(wm8900_lineout2_lp_mux,
+                           WM8900_REG_LOUTMIXCTL1, 1, wm8900_lp_mux);
 
 static const struct snd_kcontrol_new wm8900_lineout2_lp =
 SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux);
index b7488f190d2bc9d5b86da537a560fc6be9f6ca0a..d4248e00160e35a0bede71fcfbd7db785d49de89 100644 (file)
@@ -153,7 +153,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 
                        data32 &= 0xffffff;
 
-                       wm8994_bulk_write(codec->control_data,
+                       wm8994_bulk_write(wm8994->wm8994,
                                          data32 & 0xffffff,
                                          block_len / 2,
                                          (void *)(data + 8));
index 433d59a0f3efa025598cf5c63f42640120893f90..2ee23a39622c14f2cdbc072cdcdb496e8291e9c0 100644 (file)
@@ -1562,7 +1562,6 @@ static int wm8993_remove(struct snd_soc_codec *codec)
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
 
        wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
        return 0;
 }
 
index b9be9cbc460391d4530e970e3c77a0521109c2a2..adb72063d44ef6a0a5c9da1e2a53bd0d16a67825 100644 (file)
@@ -265,21 +265,21 @@ static const char *sidetone_hpf_text[] = {
        "2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz"
 };
 
-static const struct soc_enum sidetone_hpf =
-       SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text);
+static SOC_ENUM_SINGLE_DECL(sidetone_hpf,
+                           WM8994_SIDETONE, 7, sidetone_hpf_text);
 
 static const char *adc_hpf_text[] = {
        "HiFi", "Voice 1", "Voice 2", "Voice 3"
 };
 
-static const struct soc_enum aif1adc1_hpf =
-       SOC_ENUM_SINGLE(WM8994_AIF1_ADC1_FILTERS, 13, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf,
+                           WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text);
 
-static const struct soc_enum aif1adc2_hpf =
-       SOC_ENUM_SINGLE(WM8994_AIF1_ADC2_FILTERS, 13, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf,
+                           WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text);
 
-static const struct soc_enum aif2adc_hpf =
-       SOC_ENUM_SINGLE(WM8994_AIF2_ADC_FILTERS, 13, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(aif2adc_hpf,
+                           WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text);
 
 static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0);
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
@@ -501,39 +501,39 @@ static const char *aif_chan_src_text[] = {
        "Left", "Right"
 };
 
-static const struct soc_enum aif1adcl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1adcl_src,
+                           WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text);
 
-static const struct soc_enum aif1adcr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1adcr_src,
+                           WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text);
 
-static const struct soc_enum aif2adcl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2adcl_src,
+                           WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text);
 
-static const struct soc_enum aif2adcr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2adcr_src,
+                           WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text);
 
-static const struct soc_enum aif1dacl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1dacl_src,
+                           WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text);
 
-static const struct soc_enum aif1dacr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1dacr_src,
+                           WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text);
 
-static const struct soc_enum aif2dacl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacl_src,
+                           WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text);
 
-static const struct soc_enum aif2dacr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacr_src,
+                           WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text);
 
 static const char *osr_text[] = {
        "Low Power", "High Performance",
 };
 
-static const struct soc_enum dac_osr =
-       SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 0, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(dac_osr,
+                           WM8994_OVERSAMPLING, 0, osr_text);
 
-static const struct soc_enum adc_osr =
-       SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(adc_osr,
+                           WM8994_OVERSAMPLING, 1, osr_text);
 
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
@@ -690,17 +690,20 @@ static const char *wm8958_ng_text[] = {
        "30ms", "125ms", "250ms", "500ms",
 };
 
-static const struct soc_enum wm8958_aif1dac1_ng_hold =
-       SOC_ENUM_SINGLE(WM8958_AIF1_DAC1_NOISE_GATE,
-                       WM8958_AIF1DAC1_NG_THR_SHIFT, 4, wm8958_ng_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold,
+                           WM8958_AIF1_DAC1_NOISE_GATE,
+                           WM8958_AIF1DAC1_NG_THR_SHIFT,
+                           wm8958_ng_text);
 
-static const struct soc_enum wm8958_aif1dac2_ng_hold =
-       SOC_ENUM_SINGLE(WM8958_AIF1_DAC2_NOISE_GATE,
-                       WM8958_AIF1DAC2_NG_THR_SHIFT, 4, wm8958_ng_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold,
+                           WM8958_AIF1_DAC2_NOISE_GATE,
+                           WM8958_AIF1DAC2_NG_THR_SHIFT,
+                           wm8958_ng_text);
 
-static const struct soc_enum wm8958_aif2dac_ng_hold =
-       SOC_ENUM_SINGLE(WM8958_AIF2_DAC_NOISE_GATE,
-                       WM8958_AIF2DAC_NG_THR_SHIFT, 4, wm8958_ng_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold,
+                           WM8958_AIF2_DAC_NOISE_GATE,
+                           WM8958_AIF2DAC_NG_THR_SHIFT,
+                           wm8958_ng_text);
 
 static const struct snd_kcontrol_new wm8958_snd_controls[] = {
 SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
@@ -1341,8 +1344,8 @@ static const char *adc_mux_text[] = {
        "DMIC",
 };
 
-static const struct soc_enum adc_enum =
-       SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(adc_enum,
+                           0, 0, adc_mux_text);
 
 static const struct snd_kcontrol_new adcl_mux =
        SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
@@ -1478,14 +1481,14 @@ static const char *sidetone_text[] = {
        "ADC/DMIC1", "DMIC2",
 };
 
-static const struct soc_enum sidetone1_enum =
-       SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone1_enum,
+                           WM8994_SIDETONE, 0, sidetone_text);
 
 static const struct snd_kcontrol_new sidetone1_mux =
        SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);
 
-static const struct soc_enum sidetone2_enum =
-       SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone2_enum,
+                           WM8994_SIDETONE, 1, sidetone_text);
 
 static const struct snd_kcontrol_new sidetone2_mux =
        SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);
@@ -1498,22 +1501,24 @@ static const char *loopback_text[] = {
        "None", "ADCDAT",
 };
 
-static const struct soc_enum aif1_loopback_enum =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2,
-                       loopback_text);
+static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum,
+                           WM8994_AIF1_CONTROL_2,
+                           WM8994_AIF1_LOOPBACK_SHIFT,
+                           loopback_text);
 
 static const struct snd_kcontrol_new aif1_loopback =
        SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum);
 
-static const struct soc_enum aif2_loopback_enum =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2,
-                       loopback_text);
+static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum,
+                           WM8994_AIF2_CONTROL_2,
+                           WM8994_AIF2_LOOPBACK_SHIFT,
+                           loopback_text);
 
 static const struct snd_kcontrol_new aif2_loopback =
        SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum);
 
-static const struct soc_enum aif1dac_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text);
+static SOC_ENUM_SINGLE_DECL(aif1dac_enum,
+                           WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text);
 
 static const struct snd_kcontrol_new aif1dac_mux =
        SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum);
@@ -1522,8 +1527,8 @@ static const char *aif2dac_text[] = {
        "AIF2DACDAT", "AIF3DACDAT",
 };
 
-static const struct soc_enum aif2dac_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text);
+static SOC_ENUM_SINGLE_DECL(aif2dac_enum,
+                           WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text);
 
 static const struct snd_kcontrol_new aif2dac_mux =
        SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum);
@@ -1532,8 +1537,8 @@ static const char *aif2adc_text[] = {
        "AIF2ADCDAT", "AIF3DACDAT",
 };
 
-static const struct soc_enum aif2adc_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text);
+static SOC_ENUM_SINGLE_DECL(aif2adc_enum,
+                           WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text);
 
 static const struct snd_kcontrol_new aif2adc_mux =
        SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum);
@@ -1542,14 +1547,14 @@ static const char *aif3adc_text[] = {
        "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM",
 };
 
-static const struct soc_enum wm8994_aif3adc_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text);
+static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum,
+                           WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);
 
 static const struct snd_kcontrol_new wm8994_aif3adc_mux =
        SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum);
 
-static const struct soc_enum wm8958_aif3adc_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 4, aif3adc_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum,
+                           WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);
 
 static const struct snd_kcontrol_new wm8958_aif3adc_mux =
        SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);
@@ -1558,8 +1563,8 @@ static const char *mono_pcm_out_text[] = {
        "None", "AIF2ADCL", "AIF2ADCR",
 };
 
-static const struct soc_enum mono_pcm_out_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 9, 3, mono_pcm_out_text);
+static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum,
+                           WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text);
 
 static const struct snd_kcontrol_new mono_pcm_out_mux =
        SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum);
@@ -1569,14 +1574,14 @@ static const char *aif2dac_src_text[] = {
 };
 
 /* Note that these two control shouldn't be simultaneously switched to AIF3 */
-static const struct soc_enum aif2dacl_src_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 7, 2, aif2dac_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum,
+                           WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text);
 
 static const struct snd_kcontrol_new aif2dacl_src_mux =
        SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum);
 
-static const struct soc_enum aif2dacr_src_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 8, 2, aif2dac_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum,
+                           WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text);
 
 static const struct snd_kcontrol_new aif2dacr_src_mux =
        SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum);
index 70ff3772079f2186cdf2967c1c050ff95f37350b..5e3bc3c6801a6bbf9512731f6cd094b2eb41511f 100644 (file)
@@ -399,6 +399,7 @@ static struct platform_driver davinci_evm_driver = {
        .driver         = {
                .name   = "davinci_evm",
                .owner  = THIS_MODULE,
+               .pm     = &snd_soc_pm_ops,
                .of_match_table = of_match_ptr(davinci_evm_dt_ids),
        },
 };
index b7858bfa0295357bc5d3ca6d1328932595167b9e..670afa29e30d0d5b97f7c60601d1e40793b5b499 100644 (file)
@@ -263,7 +263,9 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                         unsigned int fmt)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret = 0;
 
+       pm_runtime_get_sync(mcasp->dev);
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
        case SND_SOC_DAIFMT_AC97:
@@ -317,7 +319,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                break;
 
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -354,10 +357,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                break;
 
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               break;
        }
-
-       return 0;
+out:
+       pm_runtime_put_sync(mcasp->dev);
+       return ret;
 }
 
 static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
@@ -448,7 +453,7 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
        return 0;
 }
 
-static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream,
+static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
                                    int channels)
 {
        int i;
@@ -524,12 +529,18 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream,
        return 0;
 }
 
-static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream)
+static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
 {
        int i, active_slots;
        u32 mask = 0;
        u32 busel = 0;
 
+       if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) {
+               dev_err(mcasp->dev, "tdm slot %d not supported\n",
+                       mcasp->tdm_slots);
+               return -EINVAL;
+       }
+
        active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots;
        for (i = 0; i < active_slots; i++)
                mask |= (1 << i);
@@ -539,35 +550,21 @@ static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream)
        if (!mcasp->dat_port)
                busel = TXSEL;
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               /* bit stream is MSB first  with no delay */
-               /* DSP_B mode */
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
-
-               if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
-                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
-                                      FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
-               else
-                       printk(KERN_ERR "playback tdm slot %d not supported\n",
-                               mcasp->tdm_slots);
-       } else {
-               /* bit stream is MSB first with no delay */
-               /* DSP_B mode */
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
-
-               if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
-                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
-                                      FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
-               else
-                       printk(KERN_ERR "capture tdm slot %d not supported\n",
-                               mcasp->tdm_slots);
-       }
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
+       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+                      FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+       mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+                      FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
+
+       return 0;
 }
 
 /* S/PDIF */
-static void davinci_hw_dit_param(struct davinci_mcasp *mcasp)
+static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp)
 {
        /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
           and LSB first */
@@ -589,6 +586,8 @@ static void davinci_hw_dit_param(struct davinci_mcasp *mcasp)
 
        /* Enable the DIT */
        mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+
+       return 0;
 }
 
 static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
@@ -605,13 +604,14 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
        u8 slots = mcasp->tdm_slots;
        u8 active_serializers;
        int channels;
+       int ret;
        struct snd_interval *pcm_channels = hw_param_interval(params,
                                        SNDRV_PCM_HW_PARAM_CHANNELS);
        channels = pcm_channels->min;
 
        active_serializers = (channels + slots - 1) / slots;
 
-       if (davinci_hw_common_param(mcasp, substream->stream, channels) == -EINVAL)
+       if (mcasp_common_hw_param(mcasp, substream->stream, channels) == -EINVAL)
                return -EINVAL;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                fifo_level = mcasp->txnumevt * active_serializers;
@@ -619,9 +619,12 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                fifo_level = mcasp->rxnumevt * active_serializers;
 
        if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
-               davinci_hw_dit_param(mcasp);
+               ret = mcasp_dit_hw_param(mcasp);
        else
-               davinci_hw_param(mcasp, substream->stream);
+               ret = mcasp_i2s_hw_param(mcasp, substream->stream);
+
+       if (ret)
+               return ret;
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_U8:
@@ -678,19 +681,9 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ret = pm_runtime_get_sync(mcasp->dev);
-               if (IS_ERR_VALUE(ret))
-                       dev_err(mcasp->dev, "pm_runtime_get_sync() failed\n");
                davinci_mcasp_start(mcasp, substream->stream);
                break;
-
        case SNDRV_PCM_TRIGGER_SUSPEND:
-               davinci_mcasp_stop(mcasp, substream->stream);
-               ret = pm_runtime_put_sync(mcasp->dev);
-               if (IS_ERR_VALUE(ret))
-                       dev_err(mcasp->dev, "pm_runtime_put_sync() failed\n");
-               break;
-
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                davinci_mcasp_stop(mcasp, substream->stream);
index d0c72ed261e74c37f9d2b7cde738b34aab303ad4..c84026c991347f99014dad7df74c57731b789e24 100644 (file)
@@ -326,7 +326,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
        regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
                           ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
        regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
-                          ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask));
+                          ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask));
 
        regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
                           ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
@@ -334,7 +334,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
        regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
                           ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
        regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
-                          ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask));
+                          ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
 
        esai_priv->slot_width = slot_width;
 
index 9c9f957fcae179c2d3d5525161fdbb0a0e338204..75e14033e8d8f0a7da6b1db6387d543c5a9a1acc 100644 (file)
 #define ESAI_xSMB_xS_SHIFT     0
 #define ESAI_xSMB_xS_WIDTH     16
 #define ESAI_xSMB_xS_MASK      (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT)
-#define ESAI_xSMB_xS(v)                (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK)
+#define ESAI_xSMB_xS(v)                (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMB_xS_MASK)
 
 /* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */
 #define ESAI_PRRC_PDC_SHIFT    0
index 79cee782dbbf9184264e69383b6d5a5ff1ba0fd7..a2fd7321b5a9a1bbd321f756af14fd9f071a372f 100644 (file)
@@ -160,7 +160,6 @@ static struct platform_driver imx_mc13783_audio_driver = {
        .driver = {
                .name = "imx_mc13783",
                .owner = THIS_MODULE,
-               .pm = &snd_soc_pm_ops,
        },
        .probe = imx_mc13783_probe,
        .remove = imx_mc13783_remove
index f2beae78969f6dd8e03125f92e3f288a8776f411..1cb22dd034eb63e98ac7e60e6d3ce5f719227db4 100644 (file)
@@ -33,8 +33,7 @@ struct imx_sgtl5000_data {
 
 static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct imx_sgtl5000_data *data = container_of(rtd->card,
-                                       struct imx_sgtl5000_data, card);
+       struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(rtd->card);
        struct device *dev = rtd->card->dev;
        int ret;
 
@@ -159,13 +158,15 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
        data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
 
+       platform_set_drvdata(pdev, &data->card);
+       snd_soc_card_set_drvdata(&data->card, data);
+
        ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
                goto fail;
        }
 
-       platform_set_drvdata(pdev, data);
        of_node_put(ssi_np);
        of_node_put(codec_np);
 
@@ -184,7 +185,8 @@ fail:
 
 static int imx_sgtl5000_remove(struct platform_device *pdev)
 {
-       struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(card);
 
        clk_put(data->codec_clk);
 
index 3fd76bc391de19a2431dd320d0abfbdcd9616cf5..3a3d17ce6ba40feea5dc6582693d7c1ee846ef13 100644 (file)
@@ -71,7 +71,7 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
 {
        struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
        struct imx_priv *priv = &card_priv;
-       struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+       struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
        struct device *dev = &priv->pdev->dev;
        unsigned int pll_out;
        int ret;
@@ -137,7 +137,7 @@ static int imx_wm8962_late_probe(struct snd_soc_card *card)
 {
        struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
        struct imx_priv *priv = &card_priv;
-       struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+       struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
        struct device *dev = &priv->pdev->dev;
        int ret;
 
@@ -264,13 +264,15 @@ static int imx_wm8962_probe(struct platform_device *pdev)
        data->card.late_probe = imx_wm8962_late_probe;
        data->card.set_bias_level = imx_wm8962_set_bias_level;
 
+       platform_set_drvdata(pdev, &data->card);
+       snd_soc_card_set_drvdata(&data->card, data);
+
        ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
                goto clk_fail;
        }
 
-       platform_set_drvdata(pdev, data);
        of_node_put(ssi_np);
        of_node_put(codec_np);
 
@@ -289,7 +291,8 @@ fail:
 
 static int imx_wm8962_remove(struct platform_device *pdev)
 {
-       struct imx_wm8962_data *data = platform_get_drvdata(pdev);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
 
        if (!IS_ERR(data->codec_clk))
                clk_disable_unprepare(data->codec_clk);
index 3fde9e402710f2bb16baf80b605da42772df69a0..d163e18d85d416b58be1dc5a905975c12623cfc9 100644 (file)
@@ -305,7 +305,9 @@ static int __init n810_soc_init(void)
        int err;
        struct device *dev;
 
-       if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
+       if (!of_have_populated_dt() ||
+           (!of_machine_is_compatible("nokia,n810") &&
+            !of_machine_is_compatible("nokia,n810-wimax")))
                return -ENODEV;
 
        n810_snd_device = platform_device_alloc("soc-audio", -1);
index 454f41cfc82847e98a6297b2db5822db35d717a6..3507574003913b5023f66853a50bec809d6187bf 100644 (file)
@@ -59,7 +59,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
        select SND_SOC_WM8750
        select SND_S3C2412_SOC_I2S
        help
-         Sat Y if you want to add support for SoC audio on the Jive.
+         Say Y if you want to add support for SoC audio on the Jive.
 
 config SND_SOC_SAMSUNG_SMDK_WM8580
        tristate "SoC I2S Audio support for WM8580 on SMDK"
@@ -145,11 +145,11 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380
 
 config SND_SOC_SAMSUNG_SMDK_WM9713
        tristate "SoC AC97 Audio support for SMDK with WM9713"
-       depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 || MACH_SMDKV310 || MACH_SMDKC210)
+       depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
        select SND_SOC_WM9713
        select SND_SAMSUNG_AC97
        help
-         Sat Y if you want to add support for SoC audio on the SMDK.
+         Say Y if you want to add support for SoC audio on the SMDK.
 
 config SND_SOC_SMARTQ
        tristate "SoC I2S Audio support for SmartQ board"
index dc8ff13187f7ca91ef960312f48eac732c44d938..b9dc6acbba8c55661eb0cf423a02fb9b7dda1c87 100644 (file)
@@ -1218,7 +1218,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
                        ret = regulator_allow_bypass(w->regulator, false);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
-                                        "ASoC: Failed to bypass %s: %d\n",
+                                        "ASoC: Failed to unbypass %s: %d\n",
                                         w->name, ret);
                }
 
@@ -1228,7 +1228,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
                        ret = regulator_allow_bypass(w->regulator, true);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
-                                        "ASoC: Failed to unbypass %s: %d\n",
+                                        "ASoC: Failed to bypass %s: %d\n",
                                         w->name, ret);
                }
 
@@ -3210,15 +3210,11 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
        struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
        const char *pin = (const char *)kcontrol->private_value;
 
-       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
        if (ucontrol->value.integer.value[0])
                snd_soc_dapm_enable_pin(&card->dapm, pin);
        else
                snd_soc_dapm_disable_pin(&card->dapm, pin);
 
-       mutex_unlock(&card->dapm_mutex);
-
        snd_soc_dapm_sync(&card->dapm);
        return 0;
 }
@@ -3248,7 +3244,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                        ret = regulator_allow_bypass(w->regulator, true);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
-                                        "ASoC: Failed to unbypass %s: %d\n",
+                                        "ASoC: Failed to bypass %s: %d\n",
                                         w->name, ret);
                }
                break;
@@ -3766,6 +3762,26 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
        mutex_unlock(&card->dapm_mutex);
 }
 
+/**
+ * snd_soc_dapm_enable_pin_unlocked - enable pin.
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Enables input/output pin and its parents or children widgets iff there is
+ * a valid audio route and active audio stream.
+ *
+ * Requires external locking.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                  const char *pin)
+{
+       return snd_soc_dapm_set_pin(dapm, pin, 1);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
+
 /**
  * snd_soc_dapm_enable_pin - enable pin.
  * @dapm: DAPM context
@@ -3773,17 +3789,26 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
  *
  * Enables input/output pin and its parents or children widgets iff there is
  * a valid audio route and active audio stream.
+ *
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
 int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
 {
-       return snd_soc_dapm_set_pin(dapm, pin, 1);
+       int ret;
+
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_dapm_set_pin(dapm, pin, 1);
+
+       mutex_unlock(&dapm->card->dapm_mutex);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
 
 /**
- * snd_soc_dapm_force_enable_pin - force a pin to be enabled
+ * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
  * @dapm: DAPM context
  * @pin: pin name
  *
@@ -3791,11 +3816,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
  * intended for use with microphone bias supplies used in microphone
  * jack detection.
  *
+ * Requires external locking.
+ *
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
-int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
-                                 const char *pin)
+int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                        const char *pin)
 {
        struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
 
@@ -3811,24 +3838,102 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
+
+/**
+ * snd_soc_dapm_force_enable_pin - force a pin to be enabled
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Enables input/output pin regardless of any other state.  This is
+ * intended for use with microphone bias supplies used in microphone
+ * jack detection.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
+                                 const char *pin)
+{
+       int ret;
+
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
+
+       mutex_unlock(&dapm->card->dapm_mutex);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
 
+/**
+ * snd_soc_dapm_disable_pin_unlocked - disable pin.
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Disables input/output pin and its parents or children widgets.
+ *
+ * Requires external locking.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                   const char *pin)
+{
+       return snd_soc_dapm_set_pin(dapm, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
+
 /**
  * snd_soc_dapm_disable_pin - disable pin.
  * @dapm: DAPM context
  * @pin: pin name
  *
  * Disables input/output pin and its parents or children widgets.
+ *
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
 int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
                             const char *pin)
 {
-       return snd_soc_dapm_set_pin(dapm, pin, 0);
+       int ret;
+
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_dapm_set_pin(dapm, pin, 0);
+
+       mutex_unlock(&dapm->card->dapm_mutex);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
 
+/**
+ * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Marks the specified pin as being not connected, disabling it along
+ * any parent or child widgets.  At present this is identical to
+ * snd_soc_dapm_disable_pin() but in future it will be extended to do
+ * additional things such as disabling controls which only affect
+ * paths through the pin.
+ *
+ * Requires external locking.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                              const char *pin)
+{
+       return snd_soc_dapm_set_pin(dapm, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
+
 /**
  * snd_soc_dapm_nc_pin - permanently disable pin.
  * @dapm: DAPM context
@@ -3845,7 +3950,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
  */
 int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
 {
-       return snd_soc_dapm_set_pin(dapm, pin, 0);
+       int ret;
+
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_dapm_set_pin(dapm, pin, 0);
+
+       mutex_unlock(&dapm->card->dapm_mutex);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
 
index 47e1ce771e65e0403e1ab743c677083c98452a8c..28522bd03b8e05c7b1bf5fbf4af611efe109930d 100644 (file)
@@ -1989,6 +1989,7 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card)
 
                paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
                if (paths < 0) {
+                       dpcm_path_put(&list);
                        dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
                                        fe->dai_link->name,  "playback");
                        mutex_unlock(&card->mutex);
@@ -2018,6 +2019,7 @@ capture:
 
                paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
                if (paths < 0) {
+                       dpcm_path_put(&list);
                        dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
                                        fe->dai_link->name,  "capture");
                        mutex_unlock(&card->mutex);
@@ -2082,6 +2084,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
        fe->dpcm[stream].runtime = fe_substream->runtime;
 
        if (dpcm_path_get(fe, stream, &list) <= 0) {
+               dpcm_path_put(&list);
                dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
                        fe->dai_link->name, stream ? "capture" : "playback");
        }
index e0305a1485680b18cbc85ba33a506bda799f47c1..9edd68db9f482e618e4e245a40dfbd0c94711e5d 100644 (file)
@@ -183,14 +183,16 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        drvdata->base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(drvdata->base))
                return PTR_ERR(drvdata->base);
 
-       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
-       if (!drvdata)
-               return -ENOMEM;
        platform_set_drvdata(pdev, drvdata);
        drvdata->physbase = r->start;
        if (sizeof(drvdata->physbase) > sizeof(r->start) &&
index 44b0ba4feab3bd1b43100feb457e82e290ea26dc..1bed780e21d96945d1cf913ce23fe31409df0cc4 100644 (file)
@@ -883,6 +883,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
                }
                break;
 
+       case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */
        case USB_ID(0x046d, 0x0808):
        case USB_ID(0x046d, 0x0809):
        case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */
index 32af6b741ef5a8aff8581f90b0c5d583d151a6ee..d1d72ff50347a3118c2e90d5452457b8948ad0d6 100644 (file)
@@ -328,6 +328,11 @@ static struct usbmix_name_map gamecom780_map[] = {
        {}
 };
 
+static const struct usbmix_name_map kef_x300a_map[] = {
+       { 10, NULL }, /* firmware locks up (?) when we try to access this FU */
+       { 0 }
+};
+
 /*
  * Control map entries
  */
@@ -419,6 +424,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x200c, 0x1018),
                .map = ebox44_map,
        },
+       {
+               .id = USB_ID(0x27ac, 0x1000),
+               .map = kef_x300a_map,
+       },
        { 0 } /* terminator */
 };
 
index da8b7aa3d3518d1e52532af42974fc2e3981376f..07b0b7542511e9912e830b11885e1212bbf63a76 100644 (file)
@@ -87,8 +87,8 @@ endif # BUILD_SRC
 # We process the rest of the Makefile if this is the final invocation of make
 ifeq ($(skip-makefile),)
 
-srctree                := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
-objtree                := $(CURDIR)
+srctree                := $(realpath $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR)))
+objtree                := $(realpath $(CURDIR))
 src            := $(srctree)
 obj            := $(objtree)
 
@@ -112,7 +112,7 @@ export Q VERBOSE
 
 LIBLOCKDEP_VERSION = $(LL_VERSION).$(LL_PATCHLEVEL).$(LL_EXTRAVERSION)
 
-INCLUDES = -I. -I/usr/local/include -I./uinclude $(CONFIG_INCLUDES)
+INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include $(CONFIG_INCLUDES)
 
 # Set compile option CFLAGS if not set elsewhere
 CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g
index f8465a811aa554e6510477ac0c733b2eb02bb5f4..23bd69cb5ade7014e8630e87ad89a16e2d95be71 100644 (file)
@@ -418,7 +418,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
 
 __attribute__((constructor)) static void init_preload(void)
 {
-       if (__init_state != done)
+       if (__init_state == done)
                return;
 
 #ifndef __GLIBC__
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/tools/lib/lockdep/uinclude/asm/hash.h b/tools/lib/lockdep/uinclude/asm/hash.h
new file mode 100644 (file)
index 0000000..d82b170
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_GENERIC_HASH_H
+#define __ASM_GENERIC_HASH_H
+
+/* Stub */
+
+#endif /* __ASM_GENERIC_HASH_H */
index 4c99fcb5da2769ef48067b5e6adf05806e758396..042ee8e463c98bf03d9a92e4d18dd3c01ec32162 100644 (file)
@@ -13,4 +13,9 @@ static inline int rcu_is_cpu_idle(void)
        return 1;
 }
 
+static inline bool rcu_is_watching(void)
+{
+       return false;
+}
+
 #endif
index 004cd74734b62b941cf64db1634d2774f70f6e3c..ee577ea03ba50f05a4b14379ddcd17a3f73593c0 100644 (file)
@@ -12,7 +12,7 @@ YACC = bison
 
 all : bpf_jit_disasm bpf_dbg bpf_asm
 
-bpf_jit_disasm : CFLAGS = -Wall -O2
+bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm'
 bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
 bpf_jit_disasm : bpf_jit_disasm.o
 
index 3c53ec268fbc52a5298f390a83e3802eecd156a6..02f985f3a396916ff60e4fcd8123bc109fa0dab4 100644 (file)
@@ -113,14 +113,16 @@ static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_locati
        if (!he)
                return -ENOMEM;
 
-       err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
-       if (err)
-               goto out;
+       if (ui__has_annotation()) {
+               err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+               if (err)
+                       goto out;
 
-       mx = he->mem_info;
-       err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
-       if (err)
-               goto out;
+               mx = he->mem_info;
+               err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
+               if (err)
+                       goto out;
+       }
 
        evsel->hists.stats.total_period += cost;
        hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
@@ -164,14 +166,18 @@ static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_loc
                he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
                                        1, 1, 0);
                if (he) {
-                       bx = he->branch_info;
-                       err = addr_map_symbol__inc_samples(&bx->from, evsel->idx);
-                       if (err)
-                               goto out;
-
-                       err = addr_map_symbol__inc_samples(&bx->to, evsel->idx);
-                       if (err)
-                               goto out;
+                       if (ui__has_annotation()) {
+                               bx = he->branch_info;
+                               err = addr_map_symbol__inc_samples(&bx->from,
+                                                                  evsel->idx);
+                               if (err)
+                                       goto out;
+
+                               err = addr_map_symbol__inc_samples(&bx->to,
+                                                                  evsel->idx);
+                               if (err)
+                                       goto out;
+                       }
 
                        evsel->hists.stats.total_period += 1;
                        hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
@@ -205,7 +211,9 @@ static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evs
        if (err)
                goto out;
 
-       err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+       if (ui__has_annotation())
+               err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+
        evsel->hists.stats.total_period += sample->period;
        hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
 out:
index 76cd510d34d023bf3c580ec2b3e2e217d8831cba..5f989a7d8bc2166e30d6bcbef710015f019ab252 100644 (file)
@@ -176,7 +176,7 @@ static void perf_top__record_precise_ip(struct perf_top *top,
 {
        struct annotation *notes;
        struct symbol *sym;
-       int err;
+       int err = 0;
 
        if (he == NULL || he->ms.sym == NULL ||
            ((top->sym_filter_entry == NULL ||
@@ -190,7 +190,9 @@ static void perf_top__record_precise_ip(struct perf_top *top,
                return;
 
        ip = he->ms.map->map_ip(he->ms.map, ip);
-       err = hist_entry__inc_addr_samples(he, counter, ip);
+
+       if (ui__has_annotation())
+               err = hist_entry__inc_addr_samples(he, counter, ip);
 
        pthread_mutex_unlock(&notes->lock);
 
index 896f27047ed6178fd6aed5566863fb4f4c251e84..6aa6fb6f7bd938b7ed7ccc2e7c07511b03a6cee6 100644 (file)
 # define MADV_UNMERGEABLE      13
 #endif
 
+#ifndef EFD_SEMAPHORE
+# define EFD_SEMAPHORE         1
+#endif
+
 struct tp_field {
        int offset;
        union {
@@ -279,6 +283,11 @@ static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
 
 #define SCA_STRARRAY syscall_arg__scnprintf_strarray
 
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * FIXME: Make this available to all arches as soon as the ioctl beautifier
+ *       gets rewritten to support all arches.
+ */
 static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
                                                 struct syscall_arg *arg)
 {
@@ -286,6 +295,7 @@ static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
 }
 
 #define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
+#endif /* defined(__i386__) || defined(__x86_64__) */
 
 static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
                                        struct syscall_arg *arg);
@@ -839,6 +849,10 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal
 
 #define SCA_SIGNUM syscall_arg__scnprintf_signum
 
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * FIXME: Make this available to all arches.
+ */
 #define TCGETS         0x5401
 
 static const char *tioctls[] = {
@@ -860,6 +874,7 @@ static const char *tioctls[] = {
 };
 
 static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
+#endif /* defined(__i386__) || defined(__x86_64__) */
 
 #define STRARRAY(arg, name, array) \
          .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
@@ -941,9 +956,16 @@ static struct syscall_fmt {
        { .name     = "getrlimit",  .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
        { .name     = "ioctl",      .errmsg = true,
          .arg_scnprintf = { [0] = SCA_FD, /* fd */ 
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * FIXME: Make this available to all arches.
+ */
                             [1] = SCA_STRHEXARRAY, /* cmd */
                             [2] = SCA_HEX, /* arg */ },
          .arg_parm      = { [1] = &strarray__tioctls, /* cmd */ }, },
+#else
+                            [2] = SCA_HEX, /* arg */ }, },
+#endif
        { .name     = "kill",       .errmsg = true,
          .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
        { .name     = "linkat",     .errmsg = true,
index c48d44958172b7dd8f75634ece4d909ae2d5b15b..0331ea2701a380c536facf82b8306729f23d9de3 100644 (file)
@@ -478,7 +478,7 @@ else
 endif
 
 ifeq ($(feature-libbfd), 1)
-  EXTLIBS += -lbfd
+  EXTLIBS += -lbfd -lz -liberty
 endif
 
 ifdef NO_DEMANGLE
index 12e551346fa6414d7b85c69fcee0b224283fdc0c..523b7bc1055321051d62562f1f490165ea2872b5 100644 (file)
@@ -121,7 +121,7 @@ test-libpython-version.bin:
        $(BUILD) $(FLAGS_PYTHON_EMBED)
 
 test-libbfd.bin:
-       $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
+       $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
 
 test-liberty.bin:
        $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
index 469eb679fb9d09d9e96e8687cc2051fa44f86565..3aa555ff9d89e5d7ede4c6af067170197b9ce0e8 100644 (file)
@@ -8,6 +8,8 @@
  */
 
 #include "util.h"
+#include "ui/ui.h"
+#include "sort.h"
 #include "build-id.h"
 #include "color.h"
 #include "cache.h"
@@ -489,7 +491,7 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
 {
        struct annotation *notes;
 
-       if (sym == NULL || use_browser != 1 || !sort__has_sym)
+       if (sym == NULL)
                return 0;
 
        notes = symbol__annotation(sym);
@@ -1399,3 +1401,8 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
 {
        return symbol__annotate(he->ms.sym, he->ms.map, privsize);
 }
+
+bool ui__has_annotation(void)
+{
+       return use_browser == 1 && sort__has_sym;
+}
index b2aef59d6bb29741dff0dbee40fa0c1d04f1cf65..56ad4f5287dec04bf8e94fe15c814b6abc8b42ee 100644 (file)
@@ -151,6 +151,8 @@ void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
 void disasm__purge(struct list_head *head);
 
+bool ui__has_annotation(void);
+
 int symbol__tty_annotate(struct symbol *sym, struct map *map,
                         struct perf_evsel *evsel, bool print_lines,
                         bool full_paths, int min_pcnt, int max_lines);
index 45cf10a562bd7958c9edd160ab20a0725ecb0385..dadfa7e54287b9aaa46da7227d4b0f275717ddb2 100644 (file)
@@ -87,13 +87,15 @@ static __always_inline unsigned long __ffs(unsigned long word)
        return num;
 }
 
+typedef const unsigned long __attribute__((__may_alias__)) long_alias_t;
+
 /*
  * Find the first set bit in a memory region.
  */
 static inline unsigned long
 find_first_bit(const unsigned long *addr, unsigned long size)
 {
-       const unsigned long *p = addr;
+       long_alias_t *p = (long_alias_t *) addr;
        unsigned long result = 0;
        unsigned long tmp;
 
index d248fca6d7ed7302c77d5500a79c853d3073ea07..1e15df10a88c2c1ff7b62dbfbcc05f39ffbe4cd1 100644 (file)
@@ -1091,12 +1091,12 @@ int is_valid_tracepoint(const char *event_string)
 static bool is_event_supported(u8 type, unsigned config)
 {
        bool ret = true;
+       int open_return;
        struct perf_evsel *evsel;
        struct perf_event_attr attr = {
                .type = type,
                .config = config,
                .disabled = 1,
-               .exclude_kernel = 1,
        };
        struct {
                struct thread_map map;
@@ -1108,7 +1108,20 @@ static bool is_event_supported(u8 type, unsigned config)
 
        evsel = perf_evsel__new(&attr);
        if (evsel) {
-               ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
+               open_return = perf_evsel__open(evsel, NULL, &tmap.map);
+               ret = open_return >= 0;
+
+               if (open_return == -EACCES) {
+                       /*
+                        * This happens if the paranoid value
+                        * /proc/sys/kernel/perf_event_paranoid is set to 2
+                        * Re-run with exclude_kernel set; we don't do that
+                        * by default as some ARM machines do not support it.
+                        *
+                        */
+                       evsel->attr.exclude_kernel = 1;
+                       ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
+               }
                perf_evsel__delete(evsel);
        }
 
index a8a9b6cd93a8f080a968f1cd05e7f80bb0df0ca6..d8b048c20cdee51ac894b5394b15c70a1897c106 100644 (file)
@@ -336,8 +336,8 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
                return ret;
 
        for (i = 0; i < ntevs && ret >= 0; i++) {
+               /* point.address is the addres of point.symbol + point.offset */
                offset = tevs[i].point.address - stext;
-               offset += tevs[i].point.offset;
                tevs[i].point.offset = 0;
                zfree(&tevs[i].point.symbol);
                ret = e_snprintf(buf, 32, "0x%lx", offset);
index 0b39a48e5110a00dde5fa0408c725730ba5fe8ff..5da6ce74c676722ff13ae858c1bb579ba353edbf 100644 (file)
@@ -1008,6 +1008,12 @@ static int perf_session__process_user_event(struct perf_session *session, union
                if (err == 0)
                        perf_session__set_id_hdr_size(session);
                return err;
+       case PERF_RECORD_HEADER_EVENT_TYPE:
+               /*
+                * Depreceated, but we need to handle it for sake
+                * of old data files create in pipe mode.
+                */
+               return 0;
        case PERF_RECORD_HEADER_TRACING_DATA:
                /* setup for reading amidst mmap */
                lseek(fd, file_offset, SEEK_SET);
index a9d758a3b3719a0b8db5d7b5d239c7dea5ceb34e..e89afc097d8ad2d4b818f07e02321084110e6ddc 100644 (file)
@@ -1336,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 
                        if (syms_ss && runtime_ss)
                                break;
+               } else {
+                       symsrc__destroy(ss);
                }
 
        }
index d66418237d21522df42e33a316b808c1e5962ffd..aa290c0de6f56d9e3f142d46124ee5d0688dd68d 100644 (file)
@@ -201,6 +201,7 @@ int main(int argc, char **argv)
 
        msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
        if (msgque.msq_id == -1) {
+               err = -errno;
                printf("Can't create queue\n");
                goto err_out;
        }